1/* $NetBSD: server.c,v 1.6 2019/05/02 14:57:01 taca Exp $ */
2
3/*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 *
10 * See the COPYRIGHT file distributed with this work for additional
11 * information regarding copyright ownership.
12 */
13
14/*! \file */
15
16#include <config.h>
17
18#include <inttypes.h>
19#include <stdbool.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <limits.h>
23#include <ctype.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26
27#include <isc/aes.h>
28#include <isc/app.h>
29#include <isc/base64.h>
30#include <isc/commandline.h>
31#include <isc/dir.h>
32#include <isc/file.h>
33#include <isc/hash.h>
34#include <isc/hex.h>
35#include <isc/hmac.h>
36#include <isc/httpd.h>
37#include <isc/lex.h>
38#include <isc/meminfo.h>
39#include <isc/nonce.h>
40#include <isc/parseint.h>
41#include <isc/platform.h>
42#include <isc/portset.h>
43#include <isc/print.h>
44#include <isc/refcount.h>
45#include <isc/resource.h>
46#include <isc/socket.h>
47#include <isc/stat.h>
48#include <isc/stats.h>
49#include <isc/stdio.h>
50#include <isc/string.h>
51#include <isc/task.h>
52#include <isc/timer.h>
53#include <isc/util.h>
54#include <isc/xml.h>
55
56#include <isccfg/grammar.h>
57#include <isccfg/namedconf.h>
58
59#include <bind9/check.h>
60
61#include <dns/adb.h>
62#include <dns/badcache.h>
63#include <dns/cache.h>
64#include <dns/catz.h>
65#include <dns/db.h>
66#include <dns/dispatch.h>
67#include <dns/dlz.h>
68#include <dns/dnsrps.h>
69#include <dns/dns64.h>
70#include <dns/dyndb.h>
71#include <dns/events.h>
72#include <dns/forward.h>
73#include <dns/fixedname.h>
74#include <dns/journal.h>
75#include <dns/keytable.h>
76#include <dns/keyvalues.h>
77#include <dns/lib.h>
78#include <dns/master.h>
79#include <dns/masterdump.h>
80#include <dns/nta.h>
81#include <dns/order.h>
82#include <dns/peer.h>
83#include <dns/portlist.h>
84#include <dns/private.h>
85#include <dns/rbt.h>
86#include <dns/rdataclass.h>
87#include <dns/rdatalist.h>
88#include <dns/rdataset.h>
89#include <dns/rdatastruct.h>
90#include <dns/resolver.h>
91#include <dns/rootns.h>
92#include <dns/rriterator.h>
93#include <dns/secalg.h>
94#include <dns/soa.h>
95#include <dns/stats.h>
96#include <dns/tkey.h>
97#include <dns/tsig.h>
98#include <dns/ttl.h>
99#include <dns/view.h>
100#include <dns/zone.h>
101#include <dns/zt.h>
102
103#include <dst/dst.h>
104#include <dst/result.h>
105
106#include <ns/client.h>
107#include <ns/hooks.h>
108#include <ns/listenlist.h>
109#include <ns/interfacemgr.h>
110
111#include <named/config.h>
112#include <named/control.h>
113#ifdef HAVE_GEOIP
114#include <named/geoip.h>
115#endif /* HAVE_GEOIP */
116#include <named/log.h>
117#include <named/logconf.h>
118#include <named/main.h>
119#include <named/os.h>
120#include <named/server.h>
121#include <named/statschannel.h>
122#include <named/tkeyconf.h>
123#include <named/tsigconf.h>
124#include <named/zoneconf.h>
125#ifdef HAVE_LIBSCF
126#include <named/smf_globals.h>
127#include <stdlib.h>
128#endif
129
130#ifdef HAVE_LMDB
131#include <lmdb.h>
132#define count_newzones count_newzones_db
133#define configure_newzones configure_newzones_db
134#define dumpzone dumpzone_db
135#else /* HAVE_LMDB */
136#define count_newzones count_newzones_file
137#define configure_newzones configure_newzones_file
138#define dumpzone dumpzone_file
139#endif /* HAVE_LMDB */
140
141#ifndef PATH_MAX
142#define PATH_MAX 1024
143#endif
144
145#ifndef SIZE_MAX
146#define SIZE_MAX ((size_t)-1)
147#endif
148
149#ifndef SIZE_AS_PERCENT
150#define SIZE_AS_PERCENT ((size_t)-2)
151#endif
152
153#ifdef TUNE_LARGE
154#define RESOLVER_NTASKS 523
155#define UDPBUFFERS 32768
156#define EXCLBUFFERS 32768
157#else
158#define RESOLVER_NTASKS 31
159#define UDPBUFFERS 1000
160#define EXCLBUFFERS 4096
161#endif /* TUNE_LARGE */
162
163#define MAX_TCP_TIMEOUT 65535
164
165/*%
166 * Check an operation for failure. Assumes that the function
167 * using it has a 'result' variable and a 'cleanup' label.
168 */
169#define CHECK(op) \
170 do { result = (op); \
171 if (result != ISC_R_SUCCESS) goto cleanup; \
172 } while (/*CONSTCOND*/0)
173
174#define TCHECK(op) \
175 do { tresult = (op); \
176 if (tresult != ISC_R_SUCCESS) { \
177 isc_buffer_clear(*text); \
178 goto cleanup; \
179 } \
180 } while (/*CONSTCOND*/ 0)
181
182#define CHECKM(op, msg) \
183 do { result = (op); \
184 if (result != ISC_R_SUCCESS) { \
185 isc_log_write(named_g_lctx, \
186 NAMED_LOGCATEGORY_GENERAL, \
187 NAMED_LOGMODULE_SERVER, \
188 ISC_LOG_ERROR, \
189 "%s: %s", msg, \
190 isc_result_totext(result)); \
191 goto cleanup; \
192 } \
193 } while (/*CONSTCOND*/0) \
194
195#define CHECKMF(op, msg, file) \
196 do { result = (op); \
197 if (result != ISC_R_SUCCESS) { \
198 isc_log_write(named_g_lctx, \
199 NAMED_LOGCATEGORY_GENERAL, \
200 NAMED_LOGMODULE_SERVER, \
201 ISC_LOG_ERROR, \
202 "%s '%s': %s", msg, file, \
203 isc_result_totext(result)); \
204 goto cleanup; \
205 } \
206 } while (/*CONSTCOND*/0) \
207
208#define CHECKFATAL(op, msg) \
209 do { result = (op); \
210 if (result != ISC_R_SUCCESS) \
211 fatal(msg, result); \
212 } while (/*CONSTCOND*/0) \
213
214/*%
215 * Maximum ADB size for views that share a cache. Use this limit to suppress
216 * the total of memory footprint, which should be the main reason for sharing
217 * a cache. Only effective when a finite max-cache-size is specified.
218 * This is currently defined to be 8MB.
219 */
220#define MAX_ADB_SIZE_FOR_CACHESHARE 8388608U
221
222struct named_dispatch {
223 isc_sockaddr_t addr;
224 unsigned int dispatchgen;
225 dns_dispatch_t *dispatch;
226 ISC_LINK(struct named_dispatch) link;
227};
228
229struct named_cache {
230 dns_cache_t *cache;
231 dns_view_t *primaryview;
232 bool needflush;
233 bool adbsizeadjusted;
234 dns_rdataclass_t rdclass;
235 ISC_LINK(named_cache_t) link;
236};
237
238struct dumpcontext {
239 isc_mem_t *mctx;
240 bool dumpcache;
241 bool dumpzones;
242 bool dumpadb;
243 bool dumpbad;
244 bool dumpfail;
245 FILE *fp;
246 ISC_LIST(struct viewlistentry) viewlist;
247 struct viewlistentry *view;
248 struct zonelistentry *zone;
249 dns_dumpctx_t *mdctx;
250 dns_db_t *db;
251 dns_db_t *cache;
252 isc_task_t *task;
253 dns_dbversion_t *version;
254};
255
256struct viewlistentry {
257 dns_view_t *view;
258 ISC_LINK(struct viewlistentry) link;
259 ISC_LIST(struct zonelistentry) zonelist;
260};
261
262struct zonelistentry {
263 dns_zone_t *zone;
264 ISC_LINK(struct zonelistentry) link;
265};
266
267/*%
268 * Configuration context to retain for each view that allows
269 * new zones to be added at runtime.
270 */
271typedef struct ns_cfgctx {
272 isc_mem_t * mctx;
273 cfg_parser_t * conf_parser;
274 cfg_parser_t * add_parser;
275 cfg_obj_t * config;
276 cfg_obj_t * vconfig;
277 cfg_obj_t * nzf_config;
278 cfg_aclconfctx_t * actx;
279} ns_cfgctx_t;
280
281/*%
282 * A function to write out added-zone configuration to the new_zone_file
283 * specified in 'view'. Maybe called by delete_zoneconf().
284 */
285typedef isc_result_t (*nzfwriter_t)(const cfg_obj_t *config, dns_view_t *view);
286
287/*%
288 * Holds state information for the initial zone loading process.
289 * Uses the isc_refcount structure to count the number of views
290 * with pending zone loads, dereferencing as each view finishes.
291 */
292typedef struct {
293 named_server_t *server;
294 bool reconfig;
295 isc_refcount_t refs;
296} ns_zoneload_t;
297
298typedef struct {
299 named_server_t *server;
300} catz_cb_data_t;
301
302typedef struct catz_chgzone_event {
303 ISC_EVENT_COMMON(struct catz_chgzone_event);
304 dns_catz_entry_t *entry;
305 dns_catz_zone_t *origin;
306 dns_view_t *view;
307 catz_cb_data_t *cbd;
308 bool mod;
309} catz_chgzone_event_t;
310
311typedef struct {
312 unsigned int magic;
313#define DZARG_MAGIC ISC_MAGIC('D', 'z', 'a', 'r')
314 isc_buffer_t **text;
315 isc_result_t result;
316} ns_dzarg_t;
317
318/*
319 * These zones should not leak onto the Internet.
320 */
321const char *empty_zones[] = {
322 /* RFC 1918 */
323 "10.IN-ADDR.ARPA",
324 "16.172.IN-ADDR.ARPA",
325 "17.172.IN-ADDR.ARPA",
326 "18.172.IN-ADDR.ARPA",
327 "19.172.IN-ADDR.ARPA",
328 "20.172.IN-ADDR.ARPA",
329 "21.172.IN-ADDR.ARPA",
330 "22.172.IN-ADDR.ARPA",
331 "23.172.IN-ADDR.ARPA",
332 "24.172.IN-ADDR.ARPA",
333 "25.172.IN-ADDR.ARPA",
334 "26.172.IN-ADDR.ARPA",
335 "27.172.IN-ADDR.ARPA",
336 "28.172.IN-ADDR.ARPA",
337 "29.172.IN-ADDR.ARPA",
338 "30.172.IN-ADDR.ARPA",
339 "31.172.IN-ADDR.ARPA",
340 "168.192.IN-ADDR.ARPA",
341
342 /* RFC 6598 */
343 "64.100.IN-ADDR.ARPA",
344 "65.100.IN-ADDR.ARPA",
345 "66.100.IN-ADDR.ARPA",
346 "67.100.IN-ADDR.ARPA",
347 "68.100.IN-ADDR.ARPA",
348 "69.100.IN-ADDR.ARPA",
349 "70.100.IN-ADDR.ARPA",
350 "71.100.IN-ADDR.ARPA",
351 "72.100.IN-ADDR.ARPA",
352 "73.100.IN-ADDR.ARPA",
353 "74.100.IN-ADDR.ARPA",
354 "75.100.IN-ADDR.ARPA",
355 "76.100.IN-ADDR.ARPA",
356 "77.100.IN-ADDR.ARPA",
357 "78.100.IN-ADDR.ARPA",
358 "79.100.IN-ADDR.ARPA",
359 "80.100.IN-ADDR.ARPA",
360 "81.100.IN-ADDR.ARPA",
361 "82.100.IN-ADDR.ARPA",
362 "83.100.IN-ADDR.ARPA",
363 "84.100.IN-ADDR.ARPA",
364 "85.100.IN-ADDR.ARPA",
365 "86.100.IN-ADDR.ARPA",
366 "87.100.IN-ADDR.ARPA",
367 "88.100.IN-ADDR.ARPA",
368 "89.100.IN-ADDR.ARPA",
369 "90.100.IN-ADDR.ARPA",
370 "91.100.IN-ADDR.ARPA",
371 "92.100.IN-ADDR.ARPA",
372 "93.100.IN-ADDR.ARPA",
373 "94.100.IN-ADDR.ARPA",
374 "95.100.IN-ADDR.ARPA",
375 "96.100.IN-ADDR.ARPA",
376 "97.100.IN-ADDR.ARPA",
377 "98.100.IN-ADDR.ARPA",
378 "99.100.IN-ADDR.ARPA",
379 "100.100.IN-ADDR.ARPA",
380 "101.100.IN-ADDR.ARPA",
381 "102.100.IN-ADDR.ARPA",
382 "103.100.IN-ADDR.ARPA",
383 "104.100.IN-ADDR.ARPA",
384 "105.100.IN-ADDR.ARPA",
385 "106.100.IN-ADDR.ARPA",
386 "107.100.IN-ADDR.ARPA",
387 "108.100.IN-ADDR.ARPA",
388 "109.100.IN-ADDR.ARPA",
389 "110.100.IN-ADDR.ARPA",
390 "111.100.IN-ADDR.ARPA",
391 "112.100.IN-ADDR.ARPA",
392 "113.100.IN-ADDR.ARPA",
393 "114.100.IN-ADDR.ARPA",
394 "115.100.IN-ADDR.ARPA",
395 "116.100.IN-ADDR.ARPA",
396 "117.100.IN-ADDR.ARPA",
397 "118.100.IN-ADDR.ARPA",
398 "119.100.IN-ADDR.ARPA",
399 "120.100.IN-ADDR.ARPA",
400 "121.100.IN-ADDR.ARPA",
401 "122.100.IN-ADDR.ARPA",
402 "123.100.IN-ADDR.ARPA",
403 "124.100.IN-ADDR.ARPA",
404 "125.100.IN-ADDR.ARPA",
405 "126.100.IN-ADDR.ARPA",
406 "127.100.IN-ADDR.ARPA",
407
408 /* RFC 5735 and RFC 5737 */
409 "0.IN-ADDR.ARPA", /* THIS NETWORK */
410 "127.IN-ADDR.ARPA", /* LOOPBACK */
411 "254.169.IN-ADDR.ARPA", /* LINK LOCAL */
412 "2.0.192.IN-ADDR.ARPA", /* TEST NET */
413 "100.51.198.IN-ADDR.ARPA", /* TEST NET 2 */
414 "113.0.203.IN-ADDR.ARPA", /* TEST NET 3 */
415 "255.255.255.255.IN-ADDR.ARPA", /* BROADCAST */
416
417 /* Local IPv6 Unicast Addresses */
418 "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
419 "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.IP6.ARPA",
420 /* LOCALLY ASSIGNED LOCAL ADDRESS SCOPE */
421 "D.F.IP6.ARPA",
422 "8.E.F.IP6.ARPA", /* LINK LOCAL */
423 "9.E.F.IP6.ARPA", /* LINK LOCAL */
424 "A.E.F.IP6.ARPA", /* LINK LOCAL */
425 "B.E.F.IP6.ARPA", /* LINK LOCAL */
426
427 /* Example Prefix, RFC 3849. */
428 "8.B.D.0.1.0.0.2.IP6.ARPA",
429
430 /* RFC 7534 */
431 "EMPTY.AS112.ARPA",
432
433 /* RFC 8375 */
434 "HOME.ARPA",
435
436 NULL
437};
438
439ISC_PLATFORM_NORETURN_PRE static void
440fatal(const char *msg, isc_result_t result) ISC_PLATFORM_NORETURN_POST;
441
442static void
443named_server_reload(isc_task_t *task, isc_event_t *event);
444
445static isc_result_t
446ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
447 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
448 uint16_t family, ns_listenelt_t **target);
449static isc_result_t
450ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
451 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
452 uint16_t family, ns_listenlist_t **target);
453
454static isc_result_t
455configure_forward(const cfg_obj_t *config, dns_view_t *view,
456 const dns_name_t *origin, const cfg_obj_t *forwarders,
457 const cfg_obj_t *forwardtype);
458
459static isc_result_t
460configure_alternates(const cfg_obj_t *config, dns_view_t *view,
461 const cfg_obj_t *alternates);
462
463static isc_result_t
464configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
465 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
466 dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
467 bool added, bool old_rpz_ok,
468 bool modify);
469
470static isc_result_t
471configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
472 isc_mem_t *mctx, cfg_aclconfctx_t *actx);
473
474static isc_result_t
475add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx);
476
477static void
478end_reserved_dispatches(named_server_t *server, bool all);
479
480static void
481newzone_cfgctx_destroy(void **cfgp);
482
483static inline isc_result_t
484putstr(isc_buffer_t **b, const char *str);
485
486static isc_result_t
487putmem(isc_buffer_t **b, const char *str, size_t len);
488
489static isc_result_t
490putuint8(isc_buffer_t **b, uint8_t val);
491
492static inline isc_result_t
493putnull(isc_buffer_t **b);
494
495static int
496count_zones(const cfg_obj_t *conf);
497
498#ifdef HAVE_LMDB
499static isc_result_t
500migrate_nzf(dns_view_t *view);
501
502static isc_result_t
503nzd_writable(dns_view_t *view);
504
505static isc_result_t
506nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi);
507
508static isc_result_t
509nzd_env_reopen(dns_view_t *view);
510
511static void
512nzd_env_close(dns_view_t *view);
513
514static isc_result_t
515nzd_close(MDB_txn **txnp, bool commit);
516
517static isc_result_t
518nzd_count(dns_view_t *view, int *countp);
519#else
520static isc_result_t
521nzf_append(dns_view_t *view, const cfg_obj_t *zconfig);
522#endif
523
524/*%
525 * Configure a single view ACL at '*aclp'. Get its configuration from
526 * 'vconfig' (for per-view configuration) and maybe from 'config'
527 */
528static isc_result_t
529configure_view_acl(const cfg_obj_t *vconfig, const cfg_obj_t *config,
530 const cfg_obj_t *gconfig, const char *aclname,
531 const char *acltuplename, cfg_aclconfctx_t *actx,
532 isc_mem_t *mctx, dns_acl_t **aclp)
533{
534 isc_result_t result;
535 const cfg_obj_t *maps[4];
536 const cfg_obj_t *aclobj = NULL;
537 int i = 0;
538
539 if (*aclp != NULL) {
540 dns_acl_detach(aclp);
541 }
542 if (vconfig != NULL) {
543 maps[i++] = cfg_tuple_get(vconfig, "options");
544 }
545 if (config != NULL) {
546 const cfg_obj_t *options = NULL;
547 (void)cfg_map_get(config, "options", &options);
548 if (options != NULL) {
549 maps[i++] = options;
550 }
551 }
552 if (gconfig != NULL) {
553 const cfg_obj_t *options = NULL;
554 (void)cfg_map_get(gconfig, "options", &options);
555 if (options != NULL) {
556 maps[i++] = options;
557 }
558 }
559 maps[i] = NULL;
560
561 (void)named_config_get(maps, aclname, &aclobj);
562 if (aclobj == NULL) {
563 /*
564 * No value available. *aclp == NULL.
565 */
566 return (ISC_R_SUCCESS);
567 }
568
569 if (acltuplename != NULL) {
570 /*
571 * If the ACL is given in an optional tuple, retrieve it.
572 * The parser should have ensured that a valid object be
573 * returned.
574 */
575 aclobj = cfg_tuple_get(aclobj, acltuplename);
576 }
577
578 result = cfg_acl_fromconfig(aclobj, config, named_g_lctx,
579 actx, mctx, 0, aclp);
580
581 return (result);
582}
583
584/*%
585 * Configure a sortlist at '*aclp'. Essentially the same as
586 * configure_view_acl() except it calls cfg_acl_fromconfig with a
587 * nest_level value of 2.
588 */
589static isc_result_t
590configure_view_sortlist(const cfg_obj_t *vconfig, const cfg_obj_t *config,
591 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
592 dns_acl_t **aclp)
593{
594 isc_result_t result;
595 const cfg_obj_t *maps[3];
596 const cfg_obj_t *aclobj = NULL;
597 int i = 0;
598
599 if (*aclp != NULL)
600 dns_acl_detach(aclp);
601 if (vconfig != NULL)
602 maps[i++] = cfg_tuple_get(vconfig, "options");
603 if (config != NULL) {
604 const cfg_obj_t *options = NULL;
605 (void)cfg_map_get(config, "options", &options);
606 if (options != NULL)
607 maps[i++] = options;
608 }
609 maps[i] = NULL;
610
611 (void)named_config_get(maps, "sortlist", &aclobj);
612 if (aclobj == NULL)
613 return (ISC_R_SUCCESS);
614
615 /*
616 * Use a nest level of 3 for the "top level" of the sortlist;
617 * this means each entry in the top three levels will be stored
618 * as lists of separate, nested ACLs, rather than merged together
619 * into IP tables as is usually done with ACLs.
620 */
621 result = cfg_acl_fromconfig(aclobj, config, named_g_lctx,
622 actx, mctx, 3, aclp);
623
624 return (result);
625}
626
627static isc_result_t
628configure_view_nametable(const cfg_obj_t *vconfig, const cfg_obj_t *config,
629 const char *confname, const char *conftuplename,
630 isc_mem_t *mctx, dns_rbt_t **rbtp)
631{
632 isc_result_t result;
633 const cfg_obj_t *maps[3];
634 const cfg_obj_t *obj = NULL;
635 const cfg_listelt_t *element;
636 int i = 0;
637 dns_fixedname_t fixed;
638 dns_name_t *name;
639 isc_buffer_t b;
640 const char *str;
641 const cfg_obj_t *nameobj;
642
643 if (*rbtp != NULL)
644 dns_rbt_destroy(rbtp);
645 if (vconfig != NULL)
646 maps[i++] = cfg_tuple_get(vconfig, "options");
647 if (config != NULL) {
648 const cfg_obj_t *options = NULL;
649 (void)cfg_map_get(config, "options", &options);
650 if (options != NULL)
651 maps[i++] = options;
652 }
653 maps[i] = NULL;
654
655 (void)named_config_get(maps, confname, &obj);
656 if (obj == NULL)
657 /*
658 * No value available. *rbtp == NULL.
659 */
660 return (ISC_R_SUCCESS);
661
662 if (conftuplename != NULL) {
663 obj = cfg_tuple_get(obj, conftuplename);
664 if (cfg_obj_isvoid(obj))
665 return (ISC_R_SUCCESS);
666 }
667
668 result = dns_rbt_create(mctx, NULL, NULL, rbtp);
669 if (result != ISC_R_SUCCESS)
670 return (result);
671
672 name = dns_fixedname_initname(&fixed);
673 for (element = cfg_list_first(obj);
674 element != NULL;
675 element = cfg_list_next(element)) {
676 nameobj = cfg_listelt_value(element);
677 str = cfg_obj_asstring(nameobj);
678 isc_buffer_constinit(&b, str, strlen(str));
679 isc_buffer_add(&b, strlen(str));
680 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
681 /*
682 * We don't need the node data, but need to set dummy data to
683 * avoid a partial match with an empty node. For example, if
684 * we have foo.example.com and bar.example.com, we'd get a match
685 * for baz.example.com, which is not the expected result.
686 * We simply use (void *)1 as the dummy data.
687 */
688 result = dns_rbt_addname(*rbtp, name, (void *)1);
689 if (result != ISC_R_SUCCESS) {
690 cfg_obj_log(nameobj, named_g_lctx, ISC_LOG_ERROR,
691 "failed to add %s for %s: %s",
692 str, confname, isc_result_totext(result));
693 goto cleanup;
694 }
695
696 }
697
698 return (result);
699
700 cleanup:
701 dns_rbt_destroy(rbtp);
702 return (result);
703
704}
705
706static isc_result_t
707dstkey_fromconfig(const cfg_obj_t *vconfig, const cfg_obj_t *key,
708 bool managed, dst_key_t **target, isc_mem_t *mctx)
709{
710 dns_rdataclass_t viewclass;
711 dns_rdata_dnskey_t keystruct;
712 uint32_t flags, proto, alg;
713 const char *keystr, *keynamestr;
714 unsigned char keydata[4096];
715 isc_buffer_t keydatabuf;
716 unsigned char rrdata[4096];
717 isc_buffer_t rrdatabuf;
718 isc_region_t r;
719 dns_fixedname_t fkeyname;
720 dns_name_t *keyname;
721 isc_buffer_t namebuf;
722 isc_result_t result;
723 dst_key_t *dstkey = NULL;
724
725 INSIST(target != NULL && *target == NULL);
726
727 flags = cfg_obj_asuint32(cfg_tuple_get(key, "flags"));
728 proto = cfg_obj_asuint32(cfg_tuple_get(key, "protocol"));
729 alg = cfg_obj_asuint32(cfg_tuple_get(key, "algorithm"));
730 keyname = dns_fixedname_name(&fkeyname);
731 keynamestr = cfg_obj_asstring(cfg_tuple_get(key, "name"));
732
733 if (managed) {
734 const char *initmethod;
735 initmethod = cfg_obj_asstring(cfg_tuple_get(key, "init"));
736
737 if (strcasecmp(initmethod, "initial-key") != 0) {
738 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
739 "managed key '%s': "
740 "invalid initialization method '%s'",
741 keynamestr, initmethod);
742 result = ISC_R_FAILURE;
743 goto cleanup;
744 }
745 }
746
747 if (vconfig == NULL)
748 viewclass = dns_rdataclass_in;
749 else {
750 const cfg_obj_t *classobj = cfg_tuple_get(vconfig, "class");
751 CHECK(named_config_getclass(classobj, dns_rdataclass_in,
752 &viewclass));
753 }
754 keystruct.common.rdclass = viewclass;
755 keystruct.common.rdtype = dns_rdatatype_dnskey;
756 /*
757 * The key data in keystruct is not dynamically allocated.
758 */
759 keystruct.mctx = NULL;
760
761 ISC_LINK_INIT(&keystruct.common, link);
762
763 if (flags > 0xffff)
764 CHECKM(ISC_R_RANGE, "key flags");
765 if (proto > 0xff)
766 CHECKM(ISC_R_RANGE, "key protocol");
767 if (alg > 0xff)
768 CHECKM(ISC_R_RANGE, "key algorithm");
769 keystruct.flags = (uint16_t)flags;
770 keystruct.protocol = (uint8_t)proto;
771 keystruct.algorithm = (uint8_t)alg;
772
773 isc_buffer_init(&keydatabuf, keydata, sizeof(keydata));
774 isc_buffer_init(&rrdatabuf, rrdata, sizeof(rrdata));
775
776 keystr = cfg_obj_asstring(cfg_tuple_get(key, "key"));
777 CHECK(isc_base64_decodestring(keystr, &keydatabuf));
778 isc_buffer_usedregion(&keydatabuf, &r);
779 keystruct.datalen = r.length;
780 keystruct.data = r.base;
781
782 if ((keystruct.algorithm == DST_ALG_RSASHA1) &&
783 r.length > 1 && r.base[0] == 1 && r.base[1] == 3)
784 cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
785 "%s key '%s' has a weak exponent",
786 managed ? "managed" : "trusted",
787 keynamestr);
788
789 CHECK(dns_rdata_fromstruct(NULL,
790 keystruct.common.rdclass,
791 keystruct.common.rdtype,
792 &keystruct, &rrdatabuf));
793 dns_fixedname_init(&fkeyname);
794 isc_buffer_constinit(&namebuf, keynamestr, strlen(keynamestr));
795 isc_buffer_add(&namebuf, strlen(keynamestr));
796 CHECK(dns_name_fromtext(keyname, &namebuf, dns_rootname, 0, NULL));
797 CHECK(dst_key_fromdns(keyname, viewclass, &rrdatabuf,
798 mctx, &dstkey));
799
800 *target = dstkey;
801 return (ISC_R_SUCCESS);
802
803 cleanup:
804 if (result == DST_R_NOCRYPTO) {
805 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
806 "ignoring %s key for '%s': no crypto support",
807 managed ? "managed" : "trusted",
808 keynamestr);
809 } else if (result == DST_R_UNSUPPORTEDALG) {
810 cfg_obj_log(key, named_g_lctx, ISC_LOG_WARNING,
811 "skipping %s key for '%s': %s",
812 managed ? "managed" : "trusted",
813 keynamestr, isc_result_totext(result));
814 } else {
815 cfg_obj_log(key, named_g_lctx, ISC_LOG_ERROR,
816 "configuring %s key for '%s': %s",
817 managed ? "managed" : "trusted",
818 keynamestr, isc_result_totext(result));
819 result = ISC_R_FAILURE;
820 }
821
822 if (dstkey != NULL)
823 dst_key_free(&dstkey);
824
825 return (result);
826}
827
828/*
829 * Load keys from configuration into key table. If 'keyname' is specified,
830 * only load keys matching that name. If 'managed' is true, load the key as
831 * an initializing key.
832 */
833static isc_result_t
834load_view_keys(const cfg_obj_t *keys, const cfg_obj_t *vconfig,
835 dns_view_t *view, bool managed,
836 const dns_name_t *keyname, isc_mem_t *mctx)
837{
838 const cfg_listelt_t *elt, *elt2;
839 const cfg_obj_t *key, *keylist;
840 dst_key_t *dstkey = NULL;
841 isc_result_t result;
842 dns_keytable_t *secroots = NULL;
843
844 CHECK(dns_view_getsecroots(view, &secroots));
845
846 for (elt = cfg_list_first(keys);
847 elt != NULL;
848 elt = cfg_list_next(elt))
849 {
850 keylist = cfg_listelt_value(elt);
851
852 for (elt2 = cfg_list_first(keylist);
853 elt2 != NULL;
854 elt2 = cfg_list_next(elt2))
855 {
856 key = cfg_listelt_value(elt2);
857 result = dstkey_fromconfig(vconfig, key, managed,
858 &dstkey, mctx);
859 if (result == DST_R_UNSUPPORTEDALG) {
860 result = ISC_R_SUCCESS;
861 continue;
862 }
863 if (result != ISC_R_SUCCESS) {
864 goto cleanup;
865 }
866
867 /*
868 * If keyname was specified, we only add that key.
869 */
870 if (keyname != NULL &&
871 !dns_name_equal(keyname, dst_key_name(dstkey)))
872 {
873 dst_key_free(&dstkey);
874 continue;
875 }
876
877 /*
878 * This key is taken from the configuration, so
879 * if it's a managed key then it's an
880 * initializing key; that's why 'managed'
881 * is duplicated below.
882 */
883 CHECK(dns_keytable_add(secroots, managed,
884 managed, &dstkey));
885 }
886 }
887
888 cleanup:
889 if (dstkey != NULL) {
890 dst_key_free(&dstkey);
891 }
892 if (secroots != NULL) {
893 dns_keytable_detach(&secroots);
894 }
895 if (result == DST_R_NOCRYPTO) {
896 result = ISC_R_SUCCESS;
897 }
898 return (result);
899}
900
901/*%
902 * Check whether a key has been successfully loaded.
903 */
904static bool
905keyloaded(dns_view_t *view, const dns_name_t *name) {
906 isc_result_t result;
907 dns_keytable_t *secroots = NULL;
908 dns_keynode_t *keynode = NULL;
909
910 result = dns_view_getsecroots(view, &secroots);
911 if (result != ISC_R_SUCCESS)
912 return (false);
913
914 result = dns_keytable_find(secroots, name, &keynode);
915
916 if (keynode != NULL)
917 dns_keytable_detachkeynode(secroots, &keynode);
918 if (secroots != NULL)
919 dns_keytable_detach(&secroots);
920
921 return (result == ISC_R_SUCCESS);
922}
923
924/*%
925 * Configure DNSSEC keys for a view.
926 *
927 * The per-view configuration values and the server-global defaults are read
928 * from 'vconfig' and 'config'.
929 */
930static isc_result_t
931configure_view_dnsseckeys(dns_view_t *view, const cfg_obj_t *vconfig,
932 const cfg_obj_t *config, const cfg_obj_t *bindkeys,
933 bool auto_root, isc_mem_t *mctx)
934{
935 isc_result_t result = ISC_R_SUCCESS;
936 const cfg_obj_t *view_keys = NULL;
937 const cfg_obj_t *global_keys = NULL;
938 const cfg_obj_t *view_managed_keys = NULL;
939 const cfg_obj_t *global_managed_keys = NULL;
940 const cfg_obj_t *maps[4];
941 const cfg_obj_t *voptions = NULL;
942 const cfg_obj_t *options = NULL;
943 const cfg_obj_t *obj = NULL;
944 const char *directory;
945 int i = 0;
946
947 /* We don't need trust anchors for the _bind view */
948 if (strcmp(view->name, "_bind") == 0 &&
949 view->rdclass == dns_rdataclass_chaos)
950 {
951 return (ISC_R_SUCCESS);
952 }
953
954 if (vconfig != NULL) {
955 voptions = cfg_tuple_get(vconfig, "options");
956 if (voptions != NULL) {
957 (void) cfg_map_get(voptions, "trusted-keys",
958 &view_keys);
959 (void) cfg_map_get(voptions, "managed-keys",
960 &view_managed_keys);
961 maps[i++] = voptions;
962 }
963 }
964
965 if (config != NULL) {
966 (void)cfg_map_get(config, "trusted-keys", &global_keys);
967 (void)cfg_map_get(config, "managed-keys", &global_managed_keys);
968 (void)cfg_map_get(config, "options", &options);
969 if (options != NULL) {
970 maps[i++] = options;
971 }
972 }
973
974 maps[i++] = named_g_defaults;
975 maps[i] = NULL;
976
977 result = dns_view_initsecroots(view, mctx);
978 if (result != ISC_R_SUCCESS) {
979 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
980 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
981 "couldn't create keytable");
982 return (ISC_R_UNEXPECTED);
983 }
984
985 result = dns_view_initntatable(view, named_g_taskmgr, named_g_timermgr);
986 if (result != ISC_R_SUCCESS) {
987 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
988 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
989 "couldn't create NTA table");
990 return (ISC_R_UNEXPECTED);
991 }
992
993 if (auto_root && view->rdclass == dns_rdataclass_in) {
994 const cfg_obj_t *builtin_keys = NULL;
995 const cfg_obj_t *builtin_managed_keys = NULL;
996
997 /*
998 * If bind.keys exists and is populated, it overrides
999 * the managed-keys clause hard-coded in named_g_config.
1000 */
1001 if (bindkeys != NULL) {
1002 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1003 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1004 "obtaining root key for view %s "
1005 "from '%s'",
1006 view->name, named_g_server->bindkeysfile);
1007
1008 (void)cfg_map_get(bindkeys, "trusted-keys",
1009 &builtin_keys);
1010 (void)cfg_map_get(bindkeys, "managed-keys",
1011 &builtin_managed_keys);
1012
1013 if ((builtin_keys == NULL) &&
1014 (builtin_managed_keys == NULL))
1015 isc_log_write(named_g_lctx,
1016 DNS_LOGCATEGORY_SECURITY,
1017 NAMED_LOGMODULE_SERVER,
1018 ISC_LOG_WARNING,
1019 "dnssec-validation auto: "
1020 "WARNING: root zone key "
1021 "not found");
1022 }
1023
1024 if ((builtin_keys == NULL) &&
1025 (builtin_managed_keys == NULL))
1026 {
1027 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1028 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1029 "using built-in root key for view %s",
1030 view->name);
1031
1032 (void)cfg_map_get(named_g_config, "trusted-keys",
1033 &builtin_keys);
1034 (void)cfg_map_get(named_g_config, "managed-keys",
1035 &builtin_managed_keys);
1036 }
1037
1038 if (builtin_keys != NULL)
1039 CHECK(load_view_keys(builtin_keys, vconfig, view,
1040 false, dns_rootname, mctx));
1041 if (builtin_managed_keys != NULL)
1042 CHECK(load_view_keys(builtin_managed_keys, vconfig,
1043 view, true, dns_rootname,
1044 mctx));
1045
1046 if (!keyloaded(view, dns_rootname)) {
1047 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1048 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1049 "root key not loaded");
1050 result = ISC_R_FAILURE;
1051 goto cleanup;
1052 }
1053 }
1054
1055 CHECK(load_view_keys(view_keys, vconfig, view, false,
1056 NULL, mctx));
1057 CHECK(load_view_keys(view_managed_keys, vconfig, view, true,
1058 NULL, mctx));
1059
1060 if (view->rdclass == dns_rdataclass_in) {
1061 CHECK(load_view_keys(global_keys, vconfig, view, false,
1062 NULL, mctx));
1063 CHECK(load_view_keys(global_managed_keys, vconfig, view,
1064 true, NULL, mctx));
1065 }
1066
1067 /*
1068 * Add key zone for managed keys.
1069 */
1070 obj = NULL;
1071 (void)named_config_get(maps, "managed-keys-directory", &obj);
1072 directory = (obj != NULL ? cfg_obj_asstring(obj) : NULL);
1073 if (directory != NULL)
1074 result = isc_file_isdirectory(directory);
1075 if (result != ISC_R_SUCCESS) {
1076 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
1077 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1078 "invalid managed-keys-directory %s: %s",
1079 directory, isc_result_totext(result));
1080 goto cleanup;
1081
1082 } else if (directory != NULL) {
1083 if (!isc_file_isdirwritable(directory)) {
1084 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1085 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1086 "managed-keys-directory '%s' "
1087 "is not writable", directory);
1088 result = ISC_R_NOPERM;
1089 goto cleanup;
1090 }
1091 }
1092
1093 CHECK(add_keydata_zone(view, directory, named_g_mctx));
1094
1095 cleanup:
1096 return (result);
1097}
1098
1099static isc_result_t
1100mustbesecure(const cfg_obj_t *mbs, dns_resolver_t *resolver) {
1101 const cfg_listelt_t *element;
1102 const cfg_obj_t *obj;
1103 const char *str;
1104 dns_fixedname_t fixed;
1105 dns_name_t *name;
1106 bool value;
1107 isc_result_t result;
1108 isc_buffer_t b;
1109
1110 name = dns_fixedname_initname(&fixed);
1111 for (element = cfg_list_first(mbs);
1112 element != NULL;
1113 element = cfg_list_next(element))
1114 {
1115 obj = cfg_listelt_value(element);
1116 str = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
1117 isc_buffer_constinit(&b, str, strlen(str));
1118 isc_buffer_add(&b, strlen(str));
1119 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1120 value = cfg_obj_asboolean(cfg_tuple_get(obj, "value"));
1121 CHECK(dns_resolver_setmustbesecure(resolver, name, value));
1122 }
1123
1124 result = ISC_R_SUCCESS;
1125
1126 cleanup:
1127 return (result);
1128}
1129
1130/*%
1131 * Get a dispatch appropriate for the resolver of a given view.
1132 */
1133static isc_result_t
1134get_view_querysource_dispatch(const cfg_obj_t **maps, int af,
1135 dns_dispatch_t **dispatchp, isc_dscp_t *dscpp,
1136 bool is_firstview)
1137{
1138 isc_result_t result = ISC_R_FAILURE;
1139 dns_dispatch_t *disp;
1140 isc_sockaddr_t sa;
1141 unsigned int attrs, attrmask;
1142 const cfg_obj_t *obj = NULL;
1143 unsigned int maxdispatchbuffers = UDPBUFFERS;
1144 isc_dscp_t dscp = -1;
1145
1146 switch (af) {
1147 case AF_INET:
1148 result = named_config_get(maps, "query-source", &obj);
1149 INSIST(result == ISC_R_SUCCESS);
1150 break;
1151 case AF_INET6:
1152 result = named_config_get(maps, "query-source-v6", &obj);
1153 INSIST(result == ISC_R_SUCCESS);
1154 break;
1155 default:
1156 INSIST(0);
1157 ISC_UNREACHABLE();
1158 }
1159
1160 sa = *(cfg_obj_assockaddr(obj));
1161 INSIST(isc_sockaddr_pf(&sa) == af);
1162
1163 dscp = cfg_obj_getdscp(obj);
1164 if (dscp != -1 && dscpp != NULL)
1165 *dscpp = dscp;
1166
1167 /*
1168 * If we don't support this address family, we're done!
1169 */
1170 switch (af) {
1171 case AF_INET:
1172 result = isc_net_probeipv4();
1173 break;
1174 case AF_INET6:
1175 result = isc_net_probeipv6();
1176 break;
1177 default:
1178 INSIST(0);
1179 ISC_UNREACHABLE();
1180 }
1181 if (result != ISC_R_SUCCESS)
1182 return (ISC_R_SUCCESS);
1183
1184 /*
1185 * Try to find a dispatcher that we can share.
1186 */
1187 attrs = 0;
1188 attrs |= DNS_DISPATCHATTR_UDP;
1189 switch (af) {
1190 case AF_INET:
1191 attrs |= DNS_DISPATCHATTR_IPV4;
1192 break;
1193 case AF_INET6:
1194 attrs |= DNS_DISPATCHATTR_IPV6;
1195 break;
1196 }
1197 if (isc_sockaddr_getport(&sa) == 0) {
1198 attrs |= DNS_DISPATCHATTR_EXCLUSIVE;
1199 maxdispatchbuffers = EXCLBUFFERS;
1200 } else {
1201 INSIST(obj != NULL);
1202 if (is_firstview) {
1203 cfg_obj_log(obj, named_g_lctx, ISC_LOG_INFO,
1204 "using specific query-source port "
1205 "suppresses port randomization and can be "
1206 "insecure.");
1207 }
1208 }
1209
1210 attrmask = 0;
1211 attrmask |= DNS_DISPATCHATTR_UDP;
1212 attrmask |= DNS_DISPATCHATTR_TCP;
1213 attrmask |= DNS_DISPATCHATTR_IPV4;
1214 attrmask |= DNS_DISPATCHATTR_IPV6;
1215
1216 disp = NULL;
1217 result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr,
1218 named_g_taskmgr, &sa, 4096,
1219 maxdispatchbuffers, 32768, 16411, 16433,
1220 attrs, attrmask, &disp);
1221 if (result != ISC_R_SUCCESS) {
1222 isc_sockaddr_t any;
1223 char buf[ISC_SOCKADDR_FORMATSIZE];
1224
1225 switch (af) {
1226 case AF_INET:
1227 isc_sockaddr_any(&any);
1228 break;
1229 case AF_INET6:
1230 isc_sockaddr_any6(&any);
1231 break;
1232 }
1233 if (isc_sockaddr_equal(&sa, &any))
1234 return (ISC_R_SUCCESS);
1235 isc_sockaddr_format(&sa, buf, sizeof(buf));
1236 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1237 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1238 "could not get query source dispatcher (%s)",
1239 buf);
1240 return (result);
1241 }
1242
1243 *dispatchp = disp;
1244
1245 return (ISC_R_SUCCESS);
1246}
1247
1248static isc_result_t
1249configure_order(dns_order_t *order, const cfg_obj_t *ent) {
1250 dns_rdataclass_t rdclass;
1251 dns_rdatatype_t rdtype;
1252 const cfg_obj_t *obj;
1253 dns_fixedname_t fixed;
1254 unsigned int mode = 0;
1255 const char *str;
1256 isc_buffer_t b;
1257 isc_result_t result;
1258 bool addroot;
1259
1260 result = named_config_getclass(cfg_tuple_get(ent, "class"),
1261 dns_rdataclass_any, &rdclass);
1262 if (result != ISC_R_SUCCESS)
1263 return (result);
1264
1265 result = named_config_gettype(cfg_tuple_get(ent, "type"),
1266 dns_rdatatype_any, &rdtype);
1267 if (result != ISC_R_SUCCESS)
1268 return (result);
1269
1270 obj = cfg_tuple_get(ent, "name");
1271 if (cfg_obj_isstring(obj))
1272 str = cfg_obj_asstring(obj);
1273 else
1274 str = "*";
1275 addroot = (strcmp(str, "*") == 0);
1276 isc_buffer_constinit(&b, str, strlen(str));
1277 isc_buffer_add(&b, strlen(str));
1278 dns_fixedname_init(&fixed);
1279 result = dns_name_fromtext(dns_fixedname_name(&fixed), &b,
1280 dns_rootname, 0, NULL);
1281 if (result != ISC_R_SUCCESS)
1282 return (result);
1283
1284 obj = cfg_tuple_get(ent, "ordering");
1285 INSIST(cfg_obj_isstring(obj));
1286 str = cfg_obj_asstring(obj);
1287 if (!strcasecmp(str, "fixed")) {
1288#if DNS_RDATASET_FIXED
1289 mode = DNS_RDATASETATTR_FIXEDORDER;
1290#else
1291 mode = DNS_RDATASETATTR_CYCLIC;
1292#endif /* DNS_RDATASET_FIXED */
1293 } else if (!strcasecmp(str, "random")) {
1294 mode = DNS_RDATASETATTR_RANDOMIZE;
1295 } else if (!strcasecmp(str, "cyclic")) {
1296 mode = DNS_RDATASETATTR_CYCLIC;
1297 } else if (!strcasecmp(str, "none")) {
1298 mode = DNS_RDATASETATTR_NONE;
1299 } else {
1300 INSIST(0);
1301 ISC_UNREACHABLE();
1302 }
1303
1304 /*
1305 * "*" should match everything including the root (BIND 8 compat).
1306 * As dns_name_matcheswildcard(".", "*.") returns FALSE add a
1307 * explicit entry for "." when the name is "*".
1308 */
1309 if (addroot) {
1310 result = dns_order_add(order, dns_rootname,
1311 rdtype, rdclass, mode);
1312 if (result != ISC_R_SUCCESS)
1313 return (result);
1314 }
1315
1316 return (dns_order_add(order, dns_fixedname_name(&fixed),
1317 rdtype, rdclass, mode));
1318}
1319
1320static isc_result_t
1321configure_peer(const cfg_obj_t *cpeer, isc_mem_t *mctx, dns_peer_t **peerp) {
1322 isc_netaddr_t na;
1323 dns_peer_t *peer;
1324 const cfg_obj_t *obj;
1325 const char *str;
1326 isc_result_t result;
1327 unsigned int prefixlen;
1328
1329 cfg_obj_asnetprefix(cfg_map_getname(cpeer), &na, &prefixlen);
1330
1331 peer = NULL;
1332 result = dns_peer_newprefix(mctx, &na, prefixlen, &peer);
1333 if (result != ISC_R_SUCCESS)
1334 return (result);
1335
1336 obj = NULL;
1337 (void)cfg_map_get(cpeer, "bogus", &obj);
1338 if (obj != NULL)
1339 CHECK(dns_peer_setbogus(peer, cfg_obj_asboolean(obj)));
1340
1341 obj = NULL;
1342 (void)cfg_map_get(cpeer, "provide-ixfr", &obj);
1343 if (obj != NULL)
1344 CHECK(dns_peer_setprovideixfr(peer, cfg_obj_asboolean(obj)));
1345
1346 obj = NULL;
1347 (void)cfg_map_get(cpeer, "request-expire", &obj);
1348 if (obj != NULL)
1349 CHECK(dns_peer_setrequestexpire(peer, cfg_obj_asboolean(obj)));
1350
1351 obj = NULL;
1352 (void)cfg_map_get(cpeer, "request-ixfr", &obj);
1353 if (obj != NULL)
1354 CHECK(dns_peer_setrequestixfr(peer, cfg_obj_asboolean(obj)));
1355
1356 obj = NULL;
1357 (void)cfg_map_get(cpeer, "request-nsid", &obj);
1358 if (obj != NULL)
1359 CHECK(dns_peer_setrequestnsid(peer, cfg_obj_asboolean(obj)));
1360
1361 obj = NULL;
1362 (void)cfg_map_get(cpeer, "send-cookie", &obj);
1363 if (obj != NULL)
1364 CHECK(dns_peer_setsendcookie(peer, cfg_obj_asboolean(obj)));
1365
1366 obj = NULL;
1367 (void)cfg_map_get(cpeer, "edns", &obj);
1368 if (obj != NULL)
1369 CHECK(dns_peer_setsupportedns(peer, cfg_obj_asboolean(obj)));
1370
1371 obj = NULL;
1372 (void)cfg_map_get(cpeer, "edns-udp-size", &obj);
1373 if (obj != NULL) {
1374 uint32_t udpsize = cfg_obj_asuint32(obj);
1375 if (udpsize < 512U)
1376 udpsize = 512U;
1377 if (udpsize > 4096U)
1378 udpsize = 4096U;
1379 CHECK(dns_peer_setudpsize(peer, (uint16_t)udpsize));
1380 }
1381
1382 obj = NULL;
1383 (void)cfg_map_get(cpeer, "edns-version", &obj);
1384 if (obj != NULL) {
1385 uint32_t ednsversion = cfg_obj_asuint32(obj);
1386 if (ednsversion > 255U)
1387 ednsversion = 255U;
1388 CHECK(dns_peer_setednsversion(peer, (uint8_t)ednsversion));
1389 }
1390
1391 obj = NULL;
1392 (void)cfg_map_get(cpeer, "max-udp-size", &obj);
1393 if (obj != NULL) {
1394 uint32_t udpsize = cfg_obj_asuint32(obj);
1395 if (udpsize < 512U)
1396 udpsize = 512U;
1397 if (udpsize > 4096U)
1398 udpsize = 4096U;
1399 CHECK(dns_peer_setmaxudp(peer, (uint16_t)udpsize));
1400 }
1401
1402 obj = NULL;
1403 (void)cfg_map_get(cpeer, "padding", &obj);
1404 if (obj != NULL) {
1405 uint32_t padding = cfg_obj_asuint32(obj);
1406 if (padding > 512U) {
1407 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
1408 "server padding value cannot "
1409 "exceed 512: lowering");
1410 padding = 512U;
1411 }
1412 CHECK(dns_peer_setpadding(peer, (uint16_t)padding));
1413 }
1414
1415 obj = NULL;
1416 (void)cfg_map_get(cpeer, "tcp-only", &obj);
1417 if (obj != NULL)
1418 CHECK(dns_peer_setforcetcp(peer, cfg_obj_asboolean(obj)));
1419
1420 obj = NULL;
1421 (void)cfg_map_get(cpeer, "tcp-keepalive", &obj);
1422 if (obj != NULL)
1423 CHECK(dns_peer_settcpkeepalive(peer, cfg_obj_asboolean(obj)));
1424
1425 obj = NULL;
1426 (void)cfg_map_get(cpeer, "transfers", &obj);
1427 if (obj != NULL)
1428 CHECK(dns_peer_settransfers(peer, cfg_obj_asuint32(obj)));
1429
1430 obj = NULL;
1431 (void)cfg_map_get(cpeer, "transfer-format", &obj);
1432 if (obj != NULL) {
1433 str = cfg_obj_asstring(obj);
1434 if (strcasecmp(str, "many-answers") == 0) {
1435 CHECK(dns_peer_settransferformat(peer,
1436 dns_many_answers));
1437 } else if (strcasecmp(str, "one-answer") == 0) {
1438 CHECK(dns_peer_settransferformat(peer,
1439 dns_one_answer));
1440 } else {
1441 INSIST(0);
1442 ISC_UNREACHABLE();
1443 }
1444 }
1445
1446 obj = NULL;
1447 (void)cfg_map_get(cpeer, "keys", &obj);
1448 if (obj != NULL) {
1449 result = dns_peer_setkeybycharp(peer, cfg_obj_asstring(obj));
1450 if (result != ISC_R_SUCCESS)
1451 goto cleanup;
1452 }
1453
1454 obj = NULL;
1455 if (na.family == AF_INET)
1456 (void)cfg_map_get(cpeer, "transfer-source", &obj);
1457 else
1458 (void)cfg_map_get(cpeer, "transfer-source-v6", &obj);
1459 if (obj != NULL) {
1460 result = dns_peer_settransfersource(peer,
1461 cfg_obj_assockaddr(obj));
1462 if (result != ISC_R_SUCCESS)
1463 goto cleanup;
1464 result = dns_peer_settransferdscp(peer, cfg_obj_getdscp(obj));
1465 if (result != ISC_R_SUCCESS)
1466 goto cleanup;
1467 named_add_reserved_dispatch(named_g_server,
1468 cfg_obj_assockaddr(obj));
1469 }
1470
1471 obj = NULL;
1472 if (na.family == AF_INET)
1473 (void)cfg_map_get(cpeer, "notify-source", &obj);
1474 else
1475 (void)cfg_map_get(cpeer, "notify-source-v6", &obj);
1476 if (obj != NULL) {
1477 result = dns_peer_setnotifysource(peer,
1478 cfg_obj_assockaddr(obj));
1479 if (result != ISC_R_SUCCESS)
1480 goto cleanup;
1481 result = dns_peer_setnotifydscp(peer, cfg_obj_getdscp(obj));
1482 if (result != ISC_R_SUCCESS)
1483 goto cleanup;
1484 named_add_reserved_dispatch(named_g_server,
1485 cfg_obj_assockaddr(obj));
1486 }
1487
1488 obj = NULL;
1489 if (na.family == AF_INET)
1490 (void)cfg_map_get(cpeer, "query-source", &obj);
1491 else
1492 (void)cfg_map_get(cpeer, "query-source-v6", &obj);
1493 if (obj != NULL) {
1494 result = dns_peer_setquerysource(peer,
1495 cfg_obj_assockaddr(obj));
1496 if (result != ISC_R_SUCCESS)
1497 goto cleanup;
1498 result = dns_peer_setquerydscp(peer, cfg_obj_getdscp(obj));
1499 if (result != ISC_R_SUCCESS)
1500 goto cleanup;
1501 named_add_reserved_dispatch(named_g_server,
1502 cfg_obj_assockaddr(obj));
1503 }
1504
1505 *peerp = peer;
1506 return (ISC_R_SUCCESS);
1507
1508 cleanup:
1509 dns_peer_detach(&peer);
1510 return (result);
1511}
1512
1513#ifdef HAVE_DLOPEN
1514static isc_result_t
1515configure_dyndb(const cfg_obj_t *dyndb, isc_mem_t *mctx,
1516 const dns_dyndbctx_t *dctx)
1517{
1518 isc_result_t result = ISC_R_SUCCESS;
1519 const cfg_obj_t *obj;
1520 const char *name, *library;
1521
1522 /* Get the name of the dyndb instance and the library path . */
1523 name = cfg_obj_asstring(cfg_tuple_get(dyndb, "name"));
1524 library = cfg_obj_asstring(cfg_tuple_get(dyndb, "library"));
1525
1526 obj = cfg_tuple_get(dyndb, "parameters");
1527 if (obj != NULL)
1528 result = dns_dyndb_load(library, name, cfg_obj_asstring(obj),
1529 cfg_obj_file(obj), cfg_obj_line(obj),
1530 mctx, dctx);
1531
1532 if (result != ISC_R_SUCCESS)
1533 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1534 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
1535 "dynamic database '%s' configuration failed: %s",
1536 name, isc_result_totext(result));
1537 return (result);
1538}
1539#endif
1540
1541
1542static isc_result_t
1543disable_algorithms(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1544 isc_result_t result;
1545 const cfg_obj_t *algorithms;
1546 const cfg_listelt_t *element;
1547 const char *str;
1548 dns_fixedname_t fixed;
1549 dns_name_t *name;
1550 isc_buffer_t b;
1551
1552 name = dns_fixedname_initname(&fixed);
1553 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1554 isc_buffer_constinit(&b, str, strlen(str));
1555 isc_buffer_add(&b, strlen(str));
1556 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1557
1558 algorithms = cfg_tuple_get(disabled, "algorithms");
1559 for (element = cfg_list_first(algorithms);
1560 element != NULL;
1561 element = cfg_list_next(element))
1562 {
1563 isc_textregion_t r;
1564 dns_secalg_t alg;
1565
1566 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1567 r.length = strlen(r.base);
1568
1569 result = dns_secalg_fromtext(&alg, &r);
1570 if (result != ISC_R_SUCCESS) {
1571 uint8_t ui;
1572 result = isc_parse_uint8(&ui, r.base, 10);
1573 alg = ui;
1574 }
1575 if (result != ISC_R_SUCCESS) {
1576 cfg_obj_log(cfg_listelt_value(element),
1577 named_g_lctx, ISC_LOG_ERROR,
1578 "invalid algorithm");
1579 CHECK(result);
1580 }
1581 CHECK(dns_resolver_disable_algorithm(resolver, name, alg));
1582 }
1583 cleanup:
1584 return (result);
1585}
1586
1587static isc_result_t
1588disable_ds_digests(const cfg_obj_t *disabled, dns_resolver_t *resolver) {
1589 isc_result_t result;
1590 const cfg_obj_t *digests;
1591 const cfg_listelt_t *element;
1592 const char *str;
1593 dns_fixedname_t fixed;
1594 dns_name_t *name;
1595 isc_buffer_t b;
1596
1597 name = dns_fixedname_initname(&fixed);
1598 str = cfg_obj_asstring(cfg_tuple_get(disabled, "name"));
1599 isc_buffer_constinit(&b, str, strlen(str));
1600 isc_buffer_add(&b, strlen(str));
1601 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1602
1603 digests = cfg_tuple_get(disabled, "digests");
1604 for (element = cfg_list_first(digests);
1605 element != NULL;
1606 element = cfg_list_next(element))
1607 {
1608 isc_textregion_t r;
1609 dns_dsdigest_t digest;
1610
1611 DE_CONST(cfg_obj_asstring(cfg_listelt_value(element)), r.base);
1612 r.length = strlen(r.base);
1613
1614 /* disable_ds_digests handles numeric values. */
1615 result = dns_dsdigest_fromtext(&digest, &r);
1616 if (result != ISC_R_SUCCESS) {
1617 cfg_obj_log(cfg_listelt_value(element),
1618 named_g_lctx, ISC_LOG_ERROR,
1619 "invalid algorithm");
1620 CHECK(result);
1621 }
1622 CHECK(dns_resolver_disable_ds_digest(resolver, name, digest));
1623 }
1624 cleanup:
1625 return (result);
1626}
1627
1628static bool
1629on_disable_list(const cfg_obj_t *disablelist, dns_name_t *zonename) {
1630 const cfg_listelt_t *element;
1631 dns_fixedname_t fixed;
1632 dns_name_t *name;
1633 isc_result_t result;
1634 const cfg_obj_t *value;
1635 const char *str;
1636 isc_buffer_t b;
1637
1638 name = dns_fixedname_initname(&fixed);
1639
1640 for (element = cfg_list_first(disablelist);
1641 element != NULL;
1642 element = cfg_list_next(element))
1643 {
1644 value = cfg_listelt_value(element);
1645 str = cfg_obj_asstring(value);
1646 isc_buffer_constinit(&b, str, strlen(str));
1647 isc_buffer_add(&b, strlen(str));
1648 result = dns_name_fromtext(name, &b, dns_rootname,
1649 0, NULL);
1650 RUNTIME_CHECK(result == ISC_R_SUCCESS);
1651 if (dns_name_equal(name, zonename))
1652 return (true);
1653 }
1654 return (false);
1655}
1656
1657static isc_result_t
1658check_dbtype(dns_zone_t *zone, unsigned int dbtypec, const char **dbargv,
1659 isc_mem_t *mctx)
1660{
1661 char **argv = NULL;
1662 unsigned int i;
1663 isc_result_t result = ISC_R_SUCCESS;
1664
1665 CHECK(dns_zone_getdbtype(zone, &argv, mctx));
1666
1667 /*
1668 * Check that all the arguments match.
1669 */
1670 for (i = 0; i < dbtypec; i++)
1671 if (argv[i] == NULL || strcmp(argv[i], dbargv[i]) != 0)
1672 CHECK(ISC_R_FAILURE);
1673
1674 /*
1675 * Check that there are not extra arguments.
1676 */
1677 if (i == dbtypec && argv[i] != NULL)
1678 result = ISC_R_FAILURE;
1679
1680 cleanup:
1681 isc_mem_free(mctx, argv);
1682 return (result);
1683}
1684
1685static isc_result_t
1686setquerystats(dns_zone_t *zone, isc_mem_t *mctx, dns_zonestat_level_t level) {
1687 isc_result_t result;
1688 isc_stats_t *zoneqrystats;
1689
1690 dns_zone_setstatlevel(zone, level);
1691
1692 zoneqrystats = NULL;
1693 if (level == dns_zonestat_full) {
1694 result = isc_stats_create(mctx, &zoneqrystats,
1695 ns_statscounter_max);
1696 if (result != ISC_R_SUCCESS)
1697 return (result);
1698 }
1699 dns_zone_setrequeststats(zone, zoneqrystats);
1700 if (zoneqrystats != NULL)
1701 isc_stats_detach(&zoneqrystats);
1702
1703 return (ISC_R_SUCCESS);
1704}
1705
1706static named_cache_t *
1707cachelist_find(named_cachelist_t *cachelist, const char *cachename,
1708 dns_rdataclass_t rdclass)
1709{
1710 named_cache_t *nsc;
1711
1712 for (nsc = ISC_LIST_HEAD(*cachelist);
1713 nsc != NULL;
1714 nsc = ISC_LIST_NEXT(nsc, link)) {
1715 if (nsc->rdclass == rdclass &&
1716 strcmp(dns_cache_getname(nsc->cache), cachename) == 0)
1717 return (nsc);
1718 }
1719
1720 return (NULL);
1721}
1722
1723static bool
1724cache_reusable(dns_view_t *originview, dns_view_t *view,
1725 bool new_zero_no_soattl)
1726{
1727 if (originview->rdclass != view->rdclass ||
1728 originview->checknames != view->checknames ||
1729 dns_resolver_getzeronosoattl(originview->resolver) !=
1730 new_zero_no_soattl ||
1731 originview->acceptexpired != view->acceptexpired ||
1732 originview->enablevalidation != view->enablevalidation ||
1733 originview->maxcachettl != view->maxcachettl ||
1734 originview->maxncachettl != view->maxncachettl) {
1735 return (false);
1736 }
1737
1738 return (true);
1739}
1740
1741static bool
1742cache_sharable(dns_view_t *originview, dns_view_t *view,
1743 bool new_zero_no_soattl,
1744 unsigned int new_cleaning_interval,
1745 uint64_t new_max_cache_size,
1746 uint32_t new_stale_ttl)
1747{
1748 /*
1749 * If the cache cannot even reused for the same view, it cannot be
1750 * shared with other views.
1751 */
1752 if (!cache_reusable(originview, view, new_zero_no_soattl))
1753 return (false);
1754
1755 /*
1756 * Check other cache related parameters that must be consistent among
1757 * the sharing views.
1758 */
1759 if (dns_cache_getcleaninginterval(originview->cache) !=
1760 new_cleaning_interval ||
1761 dns_cache_getservestalettl(originview->cache) != new_stale_ttl ||
1762 dns_cache_getcachesize(originview->cache) != new_max_cache_size) {
1763 return (false);
1764 }
1765
1766 return (true);
1767}
1768
1769/*
1770 * Callback from DLZ configure when the driver sets up a writeable zone
1771 */
1772static isc_result_t
1773dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
1774 dns_name_t *origin = dns_zone_getorigin(zone);
1775 dns_rdataclass_t zclass = view->rdclass;
1776 isc_result_t result;
1777
1778 result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
1779 if (result != ISC_R_SUCCESS)
1780 return (result);
1781 dns_zone_setstats(zone, named_g_server->zonestats);
1782
1783 return (named_zone_configure_writeable_dlz(dlzdb, zone,
1784 zclass, origin));
1785}
1786
1787static isc_result_t
1788dns64_reverse(dns_view_t *view, isc_mem_t *mctx, isc_netaddr_t *na,
1789 unsigned int prefixlen, const char *server,
1790 const char *contact)
1791{
1792 char reverse[48+sizeof("ip6.arpa.")] = { 0 };
1793 char buf[sizeof("x.x.")];
1794 const char *dns64_dbtype[4] = { "_dns64", "dns64", ".", "." };
1795 const char *sep = ": view ";
1796 const char *viewname = view->name;
1797 const unsigned char *s6;
1798 dns_fixedname_t fixed;
1799 dns_name_t *name;
1800 dns_zone_t *zone = NULL;
1801 int dns64_dbtypec = 4;
1802 isc_buffer_t b;
1803 isc_result_t result;
1804
1805 REQUIRE(prefixlen == 32 || prefixlen == 40 || prefixlen == 48 ||
1806 prefixlen == 56 || prefixlen == 64 || prefixlen == 96);
1807
1808 if (!strcmp(viewname, "_default")) {
1809 sep = "";
1810 viewname = "";
1811 }
1812
1813 /*
1814 * Construct the reverse name of the zone.
1815 */
1816 s6 = na->type.in6.s6_addr;
1817 while (prefixlen > 0) {
1818 prefixlen -= 8;
1819 snprintf(buf, sizeof(buf), "%x.%x.", s6[prefixlen/8] & 0xf,
1820 (s6[prefixlen/8] >> 4) & 0xf);
1821 strlcat(reverse, buf, sizeof(reverse));
1822 }
1823 strlcat(reverse, "ip6.arpa.", sizeof(reverse));
1824
1825 /*
1826 * Create the actual zone.
1827 */
1828 if (server != NULL)
1829 dns64_dbtype[2] = server;
1830 if (contact != NULL)
1831 dns64_dbtype[3] = contact;
1832 name = dns_fixedname_initname(&fixed);
1833 isc_buffer_constinit(&b, reverse, strlen(reverse));
1834 isc_buffer_add(&b, strlen(reverse));
1835 CHECK(dns_name_fromtext(name, &b, dns_rootname, 0, NULL));
1836 CHECK(dns_zone_create(&zone, mctx));
1837 CHECK(dns_zone_setorigin(zone, name));
1838 dns_zone_setview(zone, view);
1839 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
1840 dns_zone_setclass(zone, view->rdclass);
1841 dns_zone_settype(zone, dns_zone_master);
1842 dns_zone_setstats(zone, named_g_server->zonestats);
1843 CHECK(dns_zone_setdbtype(zone, dns64_dbtypec, dns64_dbtype));
1844 if (view->queryacl != NULL)
1845 dns_zone_setqueryacl(zone, view->queryacl);
1846 if (view->queryonacl != NULL)
1847 dns_zone_setqueryonacl(zone, view->queryonacl);
1848 dns_zone_setdialup(zone, dns_dialuptype_no);
1849 dns_zone_setnotifytype(zone, dns_notifytype_no);
1850 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
1851 CHECK(setquerystats(zone, mctx, dns_zonestat_none)); /* XXXMPA */
1852 CHECK(dns_view_addzone(view, zone));
1853 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
1854 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
1855 "dns64 reverse zone%s%s: %s", sep,
1856 viewname, reverse);
1857
1858cleanup:
1859 if (zone != NULL)
1860 dns_zone_detach(&zone);
1861 return (result);
1862}
1863
1864#ifdef USE_DNSRPS
1865typedef struct conf_dnsrps_ctx conf_dnsrps_ctx_t;
1866struct conf_dnsrps_ctx {
1867 isc_result_t result;
1868 char *cstr;
1869 size_t cstr_size;
1870 isc_mem_t *mctx;
1871};
1872
1873/*
1874 * Add to the DNSRPS configuration string.
1875 */
1876static bool
1877conf_dnsrps_sadd(conf_dnsrps_ctx_t *ctx, const char *p, ...) {
1878 size_t new_len, cur_len, new_cstr_size;
1879 char *new_cstr;
1880 va_list args;
1881
1882 if (ctx->cstr == NULL) {
1883 ctx->cstr = isc_mem_get(ctx->mctx, 256);
1884 if (ctx->cstr == NULL) {
1885 ctx->result = ISC_R_NOMEMORY;
1886 return (false);
1887 }
1888 ctx->cstr[0] = '\0';
1889 ctx->cstr_size = 256;
1890 }
1891
1892 cur_len = strlen(ctx->cstr);
1893 va_start(args, p);
1894 new_len = vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len,
1895 p, args) + 1;
1896 va_end(args);
1897
1898 if (cur_len + new_len <= ctx->cstr_size)
1899 return (true);
1900
1901 new_cstr_size = ((cur_len + new_len)/256 + 1) * 256;
1902 new_cstr = isc_mem_get(ctx->mctx, new_cstr_size);
1903 if (new_cstr == NULL) {
1904 ctx->result = ISC_R_NOMEMORY;
1905 return (false);
1906 }
1907
1908 memmove(new_cstr, ctx->cstr, cur_len);
1909 isc_mem_put(ctx->mctx, ctx->cstr, ctx->cstr_size);
1910 ctx->cstr_size = new_cstr_size;
1911 ctx->cstr = new_cstr;
1912
1913 /* cannot use args twice after a single va_start()on some systems */
1914 va_start(args, p);
1915 vsnprintf(ctx->cstr + cur_len, ctx->cstr_size - cur_len, p, args);
1916 va_end(args);
1917 return (true);
1918}
1919
1920/*
1921 * Get an DNSRPS configuration value using the global and view options
1922 * for the default. Return false upon failure.
1923 */
1924static bool
1925conf_dnsrps_get(const cfg_obj_t **sub_obj,
1926 const cfg_obj_t **maps ,const cfg_obj_t *obj,
1927 const char *name, conf_dnsrps_ctx_t *ctx)
1928{
1929 if (ctx != NULL && ctx->result != ISC_R_SUCCESS) {
1930 *sub_obj = NULL;
1931 return (false);
1932 }
1933
1934 *sub_obj = cfg_tuple_get(obj, name);
1935 if (cfg_obj_isvoid(*sub_obj)) {
1936 *sub_obj = NULL;
1937 if (maps != NULL &&
1938 ISC_R_SUCCESS != named_config_get(maps, name, sub_obj))
1939 *sub_obj = NULL;
1940 }
1941 return (true);
1942}
1943
1944/*
1945 * Handle a DNSRPS boolean configuration value with the global and view
1946 * options providing the default.
1947 */
1948static void
1949conf_dnsrps_yes_no(const cfg_obj_t *obj, const char* name,
1950 conf_dnsrps_ctx_t *ctx)
1951{
1952 const cfg_obj_t *sub_obj;
1953
1954 if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx))
1955 return;
1956 if (sub_obj == NULL)
1957 return;
1958 if (ctx == NULL) {
1959 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
1960 "\"%s\" without \"dnsrps-enable yes\"",
1961 name);
1962 return;
1963 }
1964
1965 conf_dnsrps_sadd(ctx, " %s %s", name,
1966 cfg_obj_asboolean(sub_obj) ? "yes" : "no");
1967}
1968
1969static void
1970conf_dnsrps_num(const cfg_obj_t *obj, const char *name,
1971 conf_dnsrps_ctx_t *ctx)
1972{
1973 const cfg_obj_t *sub_obj;
1974
1975 if (!conf_dnsrps_get(&sub_obj, NULL, obj, name, ctx))
1976 return;
1977 if (sub_obj == NULL)
1978 return;
1979 if (ctx == NULL) {
1980 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
1981 "\"%s\" without \"dnsrps-enable yes\"",
1982 name);
1983 return;
1984 }
1985
1986 conf_dnsrps_sadd(ctx, " %s %d", name, cfg_obj_asuint32(sub_obj));
1987}
1988
1989/*
1990 * Convert the parsed RPZ configuration statement to a string for
1991 * dns_rpz_new_zones().
1992 */
1993static isc_result_t
1994conf_dnsrps(dns_view_t *view, const cfg_obj_t **maps,
1995 bool nsip_enabled, bool nsdname_enabled,
1996 dns_rpz_zbits_t *nsip_on, dns_rpz_zbits_t *nsdname_on,
1997 char **rps_cstr, size_t *rps_cstr_size,
1998 const cfg_obj_t *rpz_obj, const cfg_listelt_t *zone_element)
1999{
2000 conf_dnsrps_ctx_t ctx;
2001 const cfg_obj_t *zone_obj, *obj;
2002 dns_rpz_num_t rpz_num;
2003 bool on;
2004 const char *s;
2005
2006 memset(&ctx, 0, sizeof(ctx));
2007 ctx.result = ISC_R_SUCCESS;
2008 ctx.mctx = view->mctx;
2009
2010 for (rpz_num = 0;
2011 zone_element != NULL && ctx.result == ISC_R_SUCCESS;
2012 ++rpz_num) {
2013 zone_obj = cfg_listelt_value(zone_element);
2014
2015 s = cfg_obj_asstring(cfg_tuple_get(zone_obj, "zone name"));
2016 conf_dnsrps_sadd(&ctx, "zone \"%s\"", s);
2017
2018 obj = cfg_tuple_get(zone_obj, "policy");
2019 if (!cfg_obj_isvoid(obj)) {
2020 s = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2021 conf_dnsrps_sadd(&ctx, " policy %s", s);
2022 if (strcasecmp(s, "cname") == 0) {
2023 s = cfg_obj_asstring(cfg_tuple_get(obj,
2024 "cname"));
2025 conf_dnsrps_sadd(&ctx, " %s", s);
2026 }
2027 }
2028
2029 conf_dnsrps_yes_no(zone_obj, "recursive-only", &ctx);
2030 conf_dnsrps_yes_no(zone_obj, "log", &ctx);
2031 conf_dnsrps_num(zone_obj, "max-policy-ttl", &ctx);
2032 obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2033 if (!cfg_obj_isvoid(obj)) {
2034 if (cfg_obj_asboolean(obj))
2035 *nsip_on |= DNS_RPZ_ZBIT(rpz_num);
2036 else
2037 *nsip_on &= ~DNS_RPZ_ZBIT(rpz_num);
2038 }
2039 on = ((*nsip_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2040 if (nsip_enabled != on)
2041 conf_dnsrps_sadd(&ctx, on ? " nsip-enable yes " :
2042 " nsip-enable no ");
2043 obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2044 if (!cfg_obj_isvoid(obj)) {
2045 if (cfg_obj_asboolean(obj))
2046 *nsdname_on |= DNS_RPZ_ZBIT(rpz_num);
2047 else
2048 *nsdname_on &= ~DNS_RPZ_ZBIT(rpz_num);
2049 }
2050 on = ((*nsdname_on & DNS_RPZ_ZBIT(rpz_num)) != 0);
2051 if (nsdname_enabled != on)
2052 conf_dnsrps_sadd(&ctx, on
2053 ? " nsdname-enable yes "
2054 : " nsdname-enable no ");
2055 conf_dnsrps_sadd(&ctx, ";\n");
2056 zone_element = cfg_list_next(zone_element);
2057 }
2058
2059 conf_dnsrps_yes_no(rpz_obj, "recursive-only", &ctx);
2060 conf_dnsrps_num(rpz_obj, "max-policy-ttl", &ctx);
2061 conf_dnsrps_num(rpz_obj, "min-ns-dots", &ctx);
2062 conf_dnsrps_yes_no(rpz_obj, "qname-wait-recurse", &ctx);
2063 conf_dnsrps_yes_no(rpz_obj, "break-dnssec", &ctx);
2064 if (!nsip_enabled)
2065 conf_dnsrps_sadd(&ctx, " nsip-enable no ");
2066 if (!nsdname_enabled)
2067 conf_dnsrps_sadd(&ctx, " nsdname-enable no ");
2068
2069 /*
2070 * Get the general dnsrpzd parameters from the response-policy
2071 * statement in the view and the general options.
2072 */
2073 if (conf_dnsrps_get(&obj, maps, rpz_obj, "dnsrps-options", &ctx) &&
2074 obj != NULL)
2075 conf_dnsrps_sadd(&ctx, " %s\n", cfg_obj_asstring(obj));
2076
2077 if (ctx.result == ISC_R_SUCCESS) {
2078 *rps_cstr = ctx.cstr;
2079 *rps_cstr_size = ctx.cstr_size;
2080 } else {
2081 if (ctx.cstr != NULL)
2082 isc_mem_put(ctx.mctx, ctx.cstr, ctx.cstr_size);
2083 *rps_cstr = NULL;
2084 *rps_cstr_size = 0;
2085 }
2086 return (ctx.result);
2087}
2088#endif
2089
2090static isc_result_t
2091configure_rpz_name(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2092 const char *str, const char *msg)
2093{
2094 isc_result_t result;
2095
2096 result = dns_name_fromstring(name, str, DNS_NAME_DOWNCASE, view->mctx);
2097 if (result != ISC_R_SUCCESS)
2098 cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2099 "invalid %s '%s'", msg, str);
2100 return (result);
2101}
2102
2103static isc_result_t
2104configure_rpz_name2(dns_view_t *view, const cfg_obj_t *obj, dns_name_t *name,
2105 const char *str, const dns_name_t *origin)
2106{
2107 isc_result_t result;
2108
2109 result = dns_name_fromstring2(name, str, origin, DNS_NAME_DOWNCASE,
2110 view->mctx);
2111 if (result != ISC_R_SUCCESS)
2112 cfg_obj_log(obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2113 "invalid zone '%s'", str);
2114 return (result);
2115}
2116
2117static isc_result_t
2118configure_rpz_zone(dns_view_t *view, const cfg_listelt_t *element,
2119 bool recursive_only_default,
2120 bool add_soa_default,
2121 dns_ttl_t ttl_default,
2122 uint32_t minupdateinterval_default,
2123 const dns_rpz_zone_t *old,
2124 bool *old_rpz_okp)
2125{
2126 const cfg_obj_t *rpz_obj, *obj;
2127 const char *str;
2128 dns_rpz_zone_t *zone = NULL;
2129 isc_result_t result;
2130 dns_rpz_num_t rpz_num;
2131
2132 REQUIRE(old != NULL || !*old_rpz_okp);
2133
2134 rpz_obj = cfg_listelt_value(element);
2135
2136 if (view->rpzs->p.num_zones >= DNS_RPZ_MAX_ZONES) {
2137 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2138 "limit of %d response policy zones exceeded",
2139 DNS_RPZ_MAX_ZONES);
2140 return (ISC_R_FAILURE);
2141 }
2142
2143 result = dns_rpz_new_zone(view->rpzs, &zone);
2144 if (result != ISC_R_SUCCESS) {
2145 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2146 "Error creating new RPZ zone : %s",
2147 isc_result_totext(result));
2148 return (result);
2149 }
2150
2151 obj = cfg_tuple_get(rpz_obj, "recursive-only");
2152 if (cfg_obj_isvoid(obj) ?
2153 recursive_only_default : cfg_obj_asboolean(obj))
2154 {
2155 view->rpzs->p.no_rd_ok &= ~DNS_RPZ_ZBIT(zone->num);
2156 } else {
2157 view->rpzs->p.no_rd_ok |= DNS_RPZ_ZBIT(zone->num);
2158 }
2159
2160 obj = cfg_tuple_get(rpz_obj, "log");
2161 if (!cfg_obj_isvoid(obj) && !cfg_obj_asboolean(obj)) {
2162 view->rpzs->p.no_log |= DNS_RPZ_ZBIT(zone->num);
2163 } else {
2164 view->rpzs->p.no_log &= ~DNS_RPZ_ZBIT(zone->num);
2165 }
2166
2167 obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2168 if (cfg_obj_isuint32(obj)) {
2169 zone->max_policy_ttl = cfg_obj_asuint32(obj);
2170 } else {
2171 zone->max_policy_ttl = ttl_default;
2172 }
2173
2174 obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2175 if (cfg_obj_isuint32(obj)) {
2176 zone->min_update_interval = cfg_obj_asuint32(obj);
2177 } else {
2178 zone->min_update_interval = minupdateinterval_default;
2179 }
2180
2181 if (*old_rpz_okp && zone->max_policy_ttl != old->max_policy_ttl)
2182 *old_rpz_okp = false;
2183
2184 str = cfg_obj_asstring(cfg_tuple_get(rpz_obj, "zone name"));
2185 result = configure_rpz_name(view, rpz_obj, &zone->origin, str, "zone");
2186 if (result != ISC_R_SUCCESS)
2187 return (result);
2188 if (dns_name_equal(&zone->origin, dns_rootname)) {
2189 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2190 "invalid zone name '%s'", str);
2191 return (DNS_R_EMPTYLABEL);
2192 }
2193 if (!view->rpzs->p.dnsrps_enabled) {
2194 for (rpz_num = 0;
2195 rpz_num < view->rpzs->p.num_zones - 1;
2196 ++rpz_num)
2197 {
2198 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin,
2199 &zone->origin)) {
2200 cfg_obj_log(rpz_obj, named_g_lctx,
2201 DNS_RPZ_ERROR_LEVEL,
2202 "duplicate '%s'", str);
2203 result = DNS_R_DUPLICATE;
2204 return (result);
2205 }
2206 }
2207 }
2208 if (*old_rpz_okp && !dns_name_equal(&old->origin, &zone->origin))
2209 *old_rpz_okp = false;
2210
2211 result = configure_rpz_name2(view, rpz_obj, &zone->client_ip,
2212 DNS_RPZ_CLIENT_IP_ZONE, &zone->origin);
2213 if (result != ISC_R_SUCCESS)
2214 return (result);
2215
2216 result = configure_rpz_name2(view, rpz_obj, &zone->ip,
2217 DNS_RPZ_IP_ZONE, &zone->origin);
2218 if (result != ISC_R_SUCCESS)
2219 return (result);
2220
2221 result = configure_rpz_name2(view, rpz_obj, &zone->nsdname,
2222 DNS_RPZ_NSDNAME_ZONE, &zone->origin);
2223 if (result != ISC_R_SUCCESS)
2224 return (result);
2225
2226 result = configure_rpz_name2(view, rpz_obj, &zone->nsip,
2227 DNS_RPZ_NSIP_ZONE, &zone->origin);
2228 if (result != ISC_R_SUCCESS)
2229 return (result);
2230
2231 result = configure_rpz_name(view, rpz_obj, &zone->passthru,
2232 DNS_RPZ_PASSTHRU_NAME, "name");
2233 if (result != ISC_R_SUCCESS)
2234 return (result);
2235
2236 result = configure_rpz_name(view, rpz_obj, &zone->drop,
2237 DNS_RPZ_DROP_NAME, "name");
2238 if (result != ISC_R_SUCCESS)
2239 return (result);
2240
2241 result = configure_rpz_name(view, rpz_obj, &zone->tcp_only,
2242 DNS_RPZ_TCP_ONLY_NAME, "name");
2243 if (result != ISC_R_SUCCESS)
2244 return (result);
2245
2246 obj = cfg_tuple_get(rpz_obj, "policy");
2247 if (cfg_obj_isvoid(obj)) {
2248 zone->policy = DNS_RPZ_POLICY_GIVEN;
2249 } else {
2250 str = cfg_obj_asstring(cfg_tuple_get(obj, "policy name"));
2251 zone->policy = dns_rpz_str2policy(str);
2252 INSIST(zone->policy != DNS_RPZ_POLICY_ERROR);
2253 if (zone->policy == DNS_RPZ_POLICY_CNAME) {
2254 str = cfg_obj_asstring(cfg_tuple_get(obj, "cname"));
2255 result = configure_rpz_name(view, rpz_obj, &zone->cname,
2256 str, "cname");
2257 if (result != ISC_R_SUCCESS)
2258 return (result);
2259 }
2260 }
2261 if (*old_rpz_okp && (zone->policy != old->policy ||
2262 !dns_name_equal(&old->cname, &zone->cname)))
2263 *old_rpz_okp = false;
2264
2265 obj = cfg_tuple_get(rpz_obj, "add-soa");
2266 if (cfg_obj_isvoid(obj)) {
2267 zone->addsoa = add_soa_default;
2268 } else {
2269 zone->addsoa = cfg_obj_asboolean(obj);
2270 }
2271
2272 return (ISC_R_SUCCESS);
2273}
2274
2275static isc_result_t
2276configure_rpz(dns_view_t *view, const cfg_obj_t **maps,
2277 const cfg_obj_t *rpz_obj, bool *old_rpz_okp)
2278{
2279 bool dnsrps_enabled;
2280 const cfg_listelt_t *zone_element;
2281 char *rps_cstr;
2282 size_t rps_cstr_size;
2283 const cfg_obj_t *sub_obj;
2284 bool recursive_only_default, add_soa_default;
2285 bool nsip_enabled, nsdname_enabled;
2286 dns_rpz_zbits_t nsip_on, nsdname_on;
2287 dns_ttl_t ttl_default;
2288 uint32_t minupdateinterval_default;
2289 dns_rpz_zones_t *zones;
2290 const dns_rpz_zones_t *old;
2291 dns_view_t *pview;
2292 const dns_rpz_zone_t *old_zone;
2293 isc_result_t result;
2294 int i;
2295
2296 *old_rpz_okp = false;
2297
2298 zone_element = cfg_list_first(cfg_tuple_get(rpz_obj, "zone list"));
2299 if (zone_element == NULL)
2300 return (ISC_R_SUCCESS);
2301
2302 nsip_enabled = true;
2303 sub_obj = cfg_tuple_get(rpz_obj, "nsip-enable");
2304 if (!cfg_obj_isvoid(sub_obj)) {
2305 nsip_enabled = cfg_obj_asboolean(sub_obj);
2306 }
2307 nsip_on = nsip_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2308
2309 nsdname_enabled = true;
2310 sub_obj = cfg_tuple_get(rpz_obj, "nsdname-enable");
2311 if (!cfg_obj_isvoid(sub_obj)) {
2312 nsdname_enabled = cfg_obj_asboolean(sub_obj);
2313 }
2314 nsdname_on = nsdname_enabled ? DNS_RPZ_ALL_ZBITS : 0;
2315
2316 /*
2317 * "dnsrps-enable yes|no" can be either a global or response-policy
2318 * clause.
2319 */
2320 dnsrps_enabled = false;
2321 rps_cstr = NULL;
2322 rps_cstr_size = 0;
2323 sub_obj = NULL;
2324 (void)named_config_get(maps, "dnsrps-enable", &sub_obj);
2325 if (sub_obj != NULL) {
2326 dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2327 }
2328 sub_obj = cfg_tuple_get(rpz_obj, "dnsrps-enable");
2329 if (!cfg_obj_isvoid(sub_obj)) {
2330 dnsrps_enabled = cfg_obj_asboolean(sub_obj);
2331 }
2332#ifndef USE_DNSRPS
2333 if (dnsrps_enabled) {
2334 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2335 "\"dnsrps-enable yes\" but"
2336 " without `./configure --enable-dnsrps`");
2337 return (ISC_R_FAILURE);
2338 }
2339#else
2340 if (dnsrps_enabled) {
2341 if (librpz == NULL) {
2342 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_ERROR_LEVEL,
2343 "\"dnsrps-enable yes\" but %s",
2344 librpz_lib_open_emsg.c);
2345 return (ISC_R_FAILURE);
2346 }
2347
2348 /*
2349 * Generate the DNS Response Policy Service
2350 * configuration string.
2351 */
2352 result = conf_dnsrps(view, maps,
2353 nsip_enabled, nsdname_enabled,
2354 &nsip_on, &nsdname_on,
2355 &rps_cstr, &rps_cstr_size,
2356 rpz_obj, zone_element);
2357 if (result != ISC_R_SUCCESS)
2358 return (result);
2359 }
2360#endif
2361
2362 result = dns_rpz_new_zones(&view->rpzs, rps_cstr,
2363 rps_cstr_size, view->mctx,
2364 named_g_taskmgr, named_g_timermgr);
2365 if (result != ISC_R_SUCCESS)
2366 return (result);
2367
2368 zones = view->rpzs;
2369
2370 zones->p.nsip_on = nsip_on;
2371 zones->p.nsdname_on = nsdname_on;
2372
2373 sub_obj = cfg_tuple_get(rpz_obj, "recursive-only");
2374 if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2375 recursive_only_default = false;
2376 } else {
2377 recursive_only_default = true;
2378 }
2379
2380 sub_obj = cfg_tuple_get(rpz_obj, "add-soa");
2381 if (!cfg_obj_isvoid(sub_obj) && !cfg_obj_asboolean(sub_obj)) {
2382 add_soa_default = false;
2383 } else {
2384 add_soa_default = true;
2385 }
2386
2387 sub_obj = cfg_tuple_get(rpz_obj, "break-dnssec");
2388 if (!cfg_obj_isvoid(sub_obj) && cfg_obj_asboolean(sub_obj)) {
2389 zones->p.break_dnssec = true;
2390 } else {
2391 zones->p.break_dnssec = false;
2392 }
2393
2394 sub_obj = cfg_tuple_get(rpz_obj, "max-policy-ttl");
2395 if (cfg_obj_isuint32(sub_obj))
2396 ttl_default = cfg_obj_asuint32(sub_obj);
2397 else
2398 ttl_default = DNS_RPZ_MAX_TTL_DEFAULT;
2399
2400 sub_obj = cfg_tuple_get(rpz_obj, "min-update-interval");
2401 if (cfg_obj_isuint32(sub_obj))
2402 minupdateinterval_default = cfg_obj_asuint32(sub_obj);
2403 else
2404 minupdateinterval_default = DNS_RPZ_MINUPDATEINTERVAL_DEFAULT;
2405
2406 sub_obj = cfg_tuple_get(rpz_obj, "min-ns-dots");
2407 if (cfg_obj_isuint32(sub_obj))
2408 zones->p.min_ns_labels = cfg_obj_asuint32(sub_obj) + 1;
2409 else
2410 zones->p.min_ns_labels = 2;
2411
2412 sub_obj = cfg_tuple_get(rpz_obj, "qname-wait-recurse");
2413 if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj))
2414 zones->p.qname_wait_recurse = true;
2415 else
2416 zones->p.qname_wait_recurse = false;
2417
2418 sub_obj = cfg_tuple_get(rpz_obj, "nsip-wait-recurse");
2419 if (cfg_obj_isvoid(sub_obj) || cfg_obj_asboolean(sub_obj))
2420 zones->p.nsip_wait_recurse = true;
2421 else
2422 zones->p.nsip_wait_recurse = false;
2423
2424 pview = NULL;
2425 result = dns_viewlist_find(&named_g_server->viewlist,
2426 view->name, view->rdclass, &pview);
2427 if (result == ISC_R_SUCCESS) {
2428 old = pview->rpzs;
2429 } else {
2430 old = NULL;
2431 }
2432 if (old == NULL)
2433 *old_rpz_okp = false;
2434 else
2435 *old_rpz_okp = true;
2436
2437 for (i = 0;
2438 zone_element != NULL;
2439 ++i, zone_element = cfg_list_next(zone_element)) {
2440 INSIST(old != NULL || !*old_rpz_okp);
2441 if (*old_rpz_okp && i < old->p.num_zones) {
2442 old_zone = old->zones[i];
2443 } else {
2444 *old_rpz_okp = false;
2445 old_zone = NULL;
2446 }
2447 result = configure_rpz_zone(view, zone_element,
2448 recursive_only_default,
2449 add_soa_default,
2450 ttl_default,
2451 minupdateinterval_default,
2452 old_zone, old_rpz_okp);
2453 if (result != ISC_R_SUCCESS) {
2454 if (pview != NULL)
2455 dns_view_detach(&pview);
2456 return (result);
2457 }
2458 }
2459
2460 /*
2461 * If this is a reloading and the parameters and list of policy
2462 * zones are unchanged, then use the same policy data.
2463 * Data for individual zones that must be reloaded will be merged.
2464 */
2465 if (*old_rpz_okp &&
2466 old != NULL && memcmp(&old->p, &zones->p, sizeof(zones->p)) != 0)
2467 {
2468 *old_rpz_okp = false;
2469 }
2470
2471 if (*old_rpz_okp &&
2472 (old == NULL ||
2473 old->rps_cstr == NULL) != (zones->rps_cstr == NULL))
2474 {
2475 *old_rpz_okp = false;
2476 }
2477
2478 if (*old_rpz_okp &&
2479 (zones->rps_cstr != NULL &&
2480 strcmp(old->rps_cstr, zones->rps_cstr) != 0))
2481 {
2482 *old_rpz_okp = false;
2483 }
2484
2485 if (*old_rpz_okp) {
2486 dns_rpz_detach_rpzs(&view->rpzs);
2487 dns_rpz_attach_rpzs(pview->rpzs, &view->rpzs);
2488 } else if (old != NULL && pview != NULL) {
2489 ++pview->rpzs->rpz_ver;
2490 view->rpzs->rpz_ver = pview->rpzs->rpz_ver;
2491 cfg_obj_log(rpz_obj, named_g_lctx, DNS_RPZ_DEBUG_LEVEL1,
2492 "updated RPZ policy: version %d",
2493 view->rpzs->rpz_ver);
2494 }
2495
2496 if (pview != NULL)
2497 dns_view_detach(&pview);
2498
2499 return (ISC_R_SUCCESS);
2500}
2501
2502static void
2503catz_addmodzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2504 catz_chgzone_event_t *ev = (catz_chgzone_event_t *) event0;
2505 isc_result_t result;
2506 isc_buffer_t namebuf;
2507 isc_buffer_t *confbuf;
2508 char nameb[DNS_NAME_FORMATSIZE];
2509 const cfg_obj_t *zlist = NULL;
2510 cfg_obj_t *zoneconf = NULL;
2511 cfg_obj_t *zoneobj = NULL;
2512 ns_cfgctx_t *cfg;
2513 dns_zone_t *zone = NULL;
2514
2515 cfg = (ns_cfgctx_t *) ev->view->new_zone_config;
2516 if (cfg == NULL) {
2517 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2518 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2519 "catz: allow-new-zones statement missing from "
2520 "config; cannot add zone from the catalog");
2521 goto cleanup;
2522 }
2523
2524 isc_buffer_init(&namebuf, nameb, DNS_NAME_FORMATSIZE);
2525 dns_name_totext(dns_catz_entry_getname(ev->entry), true, &namebuf);
2526 isc_buffer_putuint8(&namebuf, 0);
2527
2528 /* Zone shouldn't already exist */
2529 result = dns_zt_find(ev->view->zonetable,
2530 dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2531
2532 if (ev->mod == true) {
2533 if (result != ISC_R_SUCCESS) {
2534 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2535 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2536 "catz: error \"%s\" while trying to "
2537 "modify zone \"%s\"",
2538 isc_result_totext(result),
2539 nameb);
2540 goto cleanup;
2541 } else {
2542 if (!dns_zone_getadded(zone)) {
2543 isc_log_write(named_g_lctx,
2544 NAMED_LOGCATEGORY_GENERAL,
2545 NAMED_LOGMODULE_SERVER,
2546 ISC_LOG_WARNING,
2547 "catz: "
2548 "catz_addmodzone_taskaction: "
2549 "zone '%s' is not a dynamically "
2550 "added zone",
2551 nameb);
2552 goto cleanup;
2553 }
2554 if (dns_zone_get_parentcatz(zone) != ev->origin) {
2555 isc_log_write(named_g_lctx,
2556 NAMED_LOGCATEGORY_GENERAL,
2557 NAMED_LOGMODULE_SERVER,
2558 ISC_LOG_WARNING,
2559 "catz: catz_delzone_taskaction: "
2560 "zone '%s' exists in multiple "
2561 "catalog zones",
2562 nameb);
2563 goto cleanup;
2564 }
2565 dns_zone_detach(&zone);
2566 }
2567
2568 } else {
2569 if (result == ISC_R_SUCCESS) {
2570 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2571 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
2572 "catz: zone \"%s\" is overridden "
2573 "by explicitly configured zone",
2574 nameb);
2575 goto cleanup;
2576 } else if (result != ISC_R_NOTFOUND &&
2577 result != DNS_R_PARTIALMATCH) {
2578 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2579 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2580 "catz: error \"%s\" while trying to "
2581 "add zone \"%s\"",
2582 isc_result_totext(result),
2583 nameb);
2584 goto cleanup;
2585 } else { /* this can happen in case of DNS_R_PARTIALMATCH */
2586 if (zone != NULL)
2587 dns_zone_detach(&zone);
2588 }
2589 }
2590 RUNTIME_CHECK(zone == NULL);
2591 /* Create a config for new zone */
2592 confbuf = NULL;
2593 result = dns_catz_generate_zonecfg(ev->origin, ev->entry, &confbuf);
2594 if (result == ISC_R_SUCCESS) {
2595 cfg_parser_reset(cfg->add_parser);
2596 result = cfg_parse_buffer(cfg->add_parser, confbuf, "catz", 0,
2597 &cfg_type_addzoneconf, 0, &zoneconf);
2598 isc_buffer_free(&confbuf);
2599 }
2600 /*
2601 * Fail if either dns_catz_generate_zonecfg() or cfg_parse_buffer3()
2602 * failed.
2603 */
2604 if (result != ISC_R_SUCCESS) {
2605 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2606 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2607 "catz: error \"%s\" while trying to generate "
2608 "config for zone \"%s\"",
2609 isc_result_totext(result), nameb);
2610 goto cleanup;
2611 }
2612 CHECK(cfg_map_get(zoneconf, "zone", &zlist));
2613 if (!cfg_obj_islist(zlist))
2614 CHECK(ISC_R_FAILURE);
2615
2616 /* For now we only support adding one zone at a time */
2617 zoneobj = cfg_listelt_value(cfg_list_first(zlist));
2618
2619 /* Mark view unfrozen so that zone can be added */
2620
2621 result = isc_task_beginexclusive(task);
2622 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2623 dns_view_thaw(ev->view);
2624 result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
2625 ev->cbd->server->mctx, ev->view,
2626 &ev->cbd->server->viewlist, cfg->actx,
2627 true, false, ev->mod);
2628 dns_view_freeze(ev->view);
2629 isc_task_endexclusive(task);
2630
2631 if (result != ISC_R_SUCCESS) {
2632 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2633 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2634 "catz: failed to configure zone \"%s\" - %d",
2635 nameb, result);
2636 goto cleanup;
2637 }
2638
2639 /* Is it there yet? */
2640 CHECK(dns_zt_find(ev->view->zonetable,
2641 dns_catz_entry_getname(ev->entry), 0, NULL, &zone));
2642
2643 /*
2644 * Load the zone from the master file. If this fails, we'll
2645 * need to undo the configuration we've done already.
2646 */
2647 result = dns_zone_load(zone, true);
2648 if (result != ISC_R_SUCCESS) {
2649 dns_db_t *dbp = NULL;
2650 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2651 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
2652 "catz: dns_zone_load() failed "
2653 "with %s; reverting.",
2654 isc_result_totext(result));
2655
2656 /* If the zone loaded partially, unload it */
2657 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2658 dns_db_detach(&dbp);
2659 dns_zone_unload(zone);
2660 }
2661
2662 /* Remove the zone from the zone table */
2663 dns_zt_unmount(ev->view->zonetable, zone);
2664 goto cleanup;
2665 }
2666
2667 /* Flag the zone as having been added at runtime */
2668 dns_zone_setadded(zone, true);
2669 dns_zone_set_parentcatz(zone, ev->origin);
2670
2671 cleanup:
2672 if (zone != NULL)
2673 dns_zone_detach(&zone);
2674 if (zoneconf != NULL)
2675 cfg_obj_destroy(cfg->add_parser, &zoneconf);
2676 dns_catz_entry_detach(ev->origin, &ev->entry);
2677 dns_catz_zone_detach(&ev->origin);
2678 dns_view_detach(&ev->view);
2679 isc_event_free(ISC_EVENT_PTR(&ev));
2680}
2681
2682static void
2683catz_delzone_taskaction(isc_task_t *task, isc_event_t *event0) {
2684 catz_chgzone_event_t *ev = (catz_chgzone_event_t *) event0;
2685 isc_result_t result;
2686 dns_zone_t *zone = NULL;
2687 dns_db_t *dbp = NULL;
2688 char cname[DNS_NAME_FORMATSIZE];
2689 const char * file;
2690
2691 result = isc_task_beginexclusive(task);
2692 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2693
2694 dns_name_format(dns_catz_entry_getname(ev->entry), cname,
2695 DNS_NAME_FORMATSIZE);
2696 result = dns_zt_find(ev->view->zonetable,
2697 dns_catz_entry_getname(ev->entry), 0, NULL, &zone);
2698 if (result != ISC_R_SUCCESS) {
2699 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2700 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2701 "catz: catz_delzone_taskaction: "
2702 "zone '%s' not found", cname);
2703 goto cleanup;
2704 }
2705
2706 if (!dns_zone_getadded(zone)) {
2707 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2708 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2709 "catz: catz_delzone_taskaction: "
2710 "zone '%s' is not a dynamically added zone",
2711 cname);
2712 goto cleanup;
2713 }
2714
2715 if (dns_zone_get_parentcatz(zone) != ev->origin) {
2716 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2717 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2718 "catz: catz_delzone_taskaction: zone "
2719 "'%s' exists in multiple catalog zones",
2720 cname);
2721 goto cleanup;
2722 }
2723
2724 /* Stop answering for this zone */
2725 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
2726 dns_db_detach(&dbp);
2727 dns_zone_unload(zone);
2728 }
2729
2730 CHECK(dns_zt_unmount(ev->view->zonetable, zone));
2731 file = dns_zone_getfile(zone);
2732 if (file != NULL)
2733 isc_file_remove(file);
2734
2735 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
2736 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
2737 "catz: catz_delzone_taskaction: "
2738 "zone '%s' deleted", cname);
2739 cleanup:
2740 isc_task_endexclusive(task);
2741 if (zone != NULL)
2742 dns_zone_detach(&zone);
2743 dns_catz_entry_detach(ev->origin, &ev->entry);
2744 dns_catz_zone_detach(&ev->origin);
2745 dns_view_detach(&ev->view);
2746 isc_event_free(ISC_EVENT_PTR(&ev));
2747}
2748
2749static isc_result_t
2750catz_create_chg_task(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2751 dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata,
2752 isc_eventtype_t type)
2753{
2754 catz_chgzone_event_t *event;
2755 isc_task_t *task;
2756 isc_result_t result;
2757 isc_taskaction_t action = NULL;
2758
2759 switch (type) {
2760 case DNS_EVENT_CATZADDZONE:
2761 case DNS_EVENT_CATZMODZONE:
2762 action = catz_addmodzone_taskaction;
2763 break;
2764 case DNS_EVENT_CATZDELZONE:
2765 action = catz_delzone_taskaction;
2766 break;
2767 default:
2768 REQUIRE(0);
2769 }
2770
2771 event = (catz_chgzone_event_t *) isc_event_allocate(view->mctx, origin,
2772 type, action, NULL,
2773 sizeof(*event));
2774 if (event == NULL)
2775 return (ISC_R_NOMEMORY);
2776
2777 event->cbd = (catz_cb_data_t *) udata;
2778 event->entry = NULL;
2779 event->origin = NULL;
2780 event->view = NULL;
2781 event->mod = (type == DNS_EVENT_CATZMODZONE);
2782 dns_catz_entry_attach(entry, &event->entry);
2783 dns_catz_zone_attach(origin, &event->origin);
2784 dns_view_attach(view, &event->view);
2785
2786 task = NULL;
2787 result = isc_taskmgr_excltask(taskmgr, &task);
2788 REQUIRE(result == ISC_R_SUCCESS);
2789 isc_task_send(task, ISC_EVENT_PTR(&event));
2790 isc_task_detach(&task);
2791
2792 return (ISC_R_SUCCESS);
2793}
2794
2795static isc_result_t
2796catz_addzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2797 dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata)
2798{
2799 return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2800 DNS_EVENT_CATZADDZONE));
2801}
2802
2803static isc_result_t
2804catz_delzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2805 dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata)
2806{
2807 return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2808 DNS_EVENT_CATZDELZONE));
2809}
2810
2811static isc_result_t
2812catz_modzone(dns_catz_entry_t *entry, dns_catz_zone_t *origin,
2813 dns_view_t *view, isc_taskmgr_t *taskmgr, void *udata)
2814{
2815 return (catz_create_chg_task(entry, origin, view, taskmgr, udata,
2816 DNS_EVENT_CATZMODZONE));
2817}
2818
2819static isc_result_t
2820configure_catz_zone(dns_view_t *view, const cfg_obj_t *config,
2821 const cfg_listelt_t *element)
2822{
2823 const cfg_obj_t *catz_obj, *obj;
2824 dns_catz_zone_t *zone = NULL;
2825 const char *str;
2826 isc_result_t result;
2827 dns_name_t origin;
2828 dns_catz_options_t *opts;
2829 dns_view_t *pview = NULL;
2830
2831 dns_name_init(&origin, NULL);
2832 catz_obj = cfg_listelt_value(element);
2833
2834 str = cfg_obj_asstring(cfg_tuple_get(catz_obj, "zone name"));
2835
2836 result = dns_name_fromstring(&origin, str, DNS_NAME_DOWNCASE,
2837 view->mctx);
2838 if (result == ISC_R_SUCCESS && dns_name_equal(&origin, dns_rootname))
2839 result = DNS_R_EMPTYLABEL;
2840
2841 if (result != ISC_R_SUCCESS) {
2842 cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
2843 "catz: invalid zone name '%s'", str);
2844 goto cleanup;
2845 }
2846
2847 result = dns_catz_add_zone(view->catzs, &origin, &zone);
2848 if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS) {
2849 cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
2850 "catz: unable to create catalog zone '%s', "
2851 "error %s",
2852 str, isc_result_totext(result));
2853 goto cleanup;
2854 }
2855
2856 if (result == ISC_R_EXISTS) {
2857 isc_ht_iter_t *it = NULL;
2858
2859 result = dns_viewlist_find(&named_g_server->viewlist,
2860 view->name,
2861 view->rdclass, &pview);
2862 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2863
2864 /*
2865 * xxxwpk todo: reconfigure the zone!!!!
2866 */
2867 cfg_obj_log(catz_obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
2868 "catz: catalog zone '%s' will not be reconfigured",
2869 str);
2870 /*
2871 * We have to walk through all the member zones and attach
2872 * them to current view
2873 */
2874 result = dns_catz_get_iterator(zone, &it);
2875 if (result != ISC_R_SUCCESS) {
2876 cfg_obj_log(catz_obj, named_g_lctx,
2877 DNS_CATZ_ERROR_LEVEL,
2878 "catz: unable to create iterator");
2879 goto cleanup;
2880 }
2881
2882 for (result = isc_ht_iter_first(it);
2883 result == ISC_R_SUCCESS;
2884 result = isc_ht_iter_next(it))
2885 {
2886 dns_name_t *name = NULL;
2887 dns_zone_t *dnszone = NULL;
2888 dns_catz_entry_t *entry = NULL;
2889 isc_result_t tresult;
2890
2891 isc_ht_iter_current(it, (void **) &entry);
2892 name = dns_catz_entry_getname(entry);
2893
2894 tresult = dns_view_findzone(pview, name, &dnszone);
2895 RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
2896
2897 dns_zone_setview(dnszone, view);
2898 dns_view_addzone(view, dnszone);
2899
2900 /*
2901 * The dns_view_findzone() call above increments the
2902 * zone's reference count, which we need to decrement
2903 * back. However, as dns_zone_detach() sets the
2904 * supplied pointer to NULL, calling it is deferred
2905 * until the dnszone variable is no longer used.
2906 */
2907 dns_zone_detach(&dnszone);
2908 }
2909
2910 isc_ht_iter_destroy(&it);
2911
2912 result = ISC_R_SUCCESS;
2913 }
2914
2915 dns_catz_zone_resetdefoptions(zone);
2916 opts = dns_catz_zone_getdefoptions(zone);
2917
2918 obj = cfg_tuple_get(catz_obj, "default-masters");
2919 if (obj != NULL && cfg_obj_istuple(obj))
2920 result = named_config_getipandkeylist(config, obj,
2921 view->mctx, &opts->masters);
2922
2923 obj = cfg_tuple_get(catz_obj, "in-memory");
2924 if (obj != NULL && cfg_obj_isboolean(obj))
2925 opts->in_memory = cfg_obj_asboolean(obj);
2926
2927 obj = cfg_tuple_get(catz_obj, "zone-directory");
2928 if (!opts->in_memory && obj != NULL && cfg_obj_isstring(obj)) {
2929 opts->zonedir = isc_mem_strdup(view->mctx,
2930 cfg_obj_asstring(obj));
2931 if (isc_file_isdirectory(opts->zonedir) != ISC_R_SUCCESS) {
2932 cfg_obj_log(obj, named_g_lctx, DNS_CATZ_ERROR_LEVEL,
2933 "catz: zone-directory '%s' "
2934 "not found; zone files will not be "
2935 "saved", opts->zonedir);
2936 opts->in_memory = true;
2937 }
2938 }
2939
2940 obj = cfg_tuple_get(catz_obj, "min-update-interval");
2941 if (obj != NULL && cfg_obj_isuint32(obj))
2942 opts->min_update_interval = cfg_obj_asuint32(obj);
2943
2944 cleanup:
2945 if (pview != NULL)
2946 dns_view_detach(&pview);
2947 dns_name_free(&origin, view->mctx);
2948
2949 return (result);
2950}
2951
2952static catz_cb_data_t ns_catz_cbdata;
2953static dns_catz_zonemodmethods_t ns_catz_zonemodmethods = {
2954 catz_addzone,
2955 catz_modzone,
2956 catz_delzone,
2957 &ns_catz_cbdata
2958};
2959
2960static isc_result_t
2961configure_catz(dns_view_t *view, const cfg_obj_t *config,
2962 const cfg_obj_t *catz_obj)
2963{
2964 const cfg_listelt_t *zone_element;
2965 const dns_catz_zones_t *old = NULL;
2966 dns_view_t *pview = NULL;
2967 isc_result_t result;
2968
2969 /* xxxwpk TODO do it cleaner, once, somewhere */
2970 ns_catz_cbdata.server = named_g_server;
2971
2972 zone_element = cfg_list_first(cfg_tuple_get(catz_obj, "zone list"));
2973 if (zone_element == NULL)
2974 return (ISC_R_SUCCESS);
2975
2976 CHECK(dns_catz_new_zones(&view->catzs, &ns_catz_zonemodmethods,
2977 view->mctx, named_g_taskmgr,
2978 named_g_timermgr));
2979
2980 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
2981 view->rdclass, &pview);
2982 if (result == ISC_R_SUCCESS)
2983 old = pview->catzs;
2984
2985 if (old != NULL) {
2986 dns_catz_catzs_detach(&view->catzs);
2987 dns_catz_catzs_attach(pview->catzs, &view->catzs);
2988 dns_catz_prereconfig(view->catzs);
2989 }
2990
2991 while (zone_element != NULL) {
2992 CHECK(configure_catz_zone(view, config, zone_element));
2993 zone_element = cfg_list_next(zone_element);
2994 }
2995
2996 if (old != NULL)
2997 dns_catz_postreconfig(view->catzs);
2998
2999 result = ISC_R_SUCCESS;
3000
3001 cleanup:
3002 if (pview != NULL)
3003 dns_view_detach(&pview);
3004
3005 return (result);
3006}
3007
3008#define CHECK_RRL(cond, pat, val1, val2) \
3009 do { \
3010 if (!(cond)) { \
3011 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, \
3012 pat, val1, val2); \
3013 result = ISC_R_RANGE; \
3014 goto cleanup; \
3015 } \
3016 } while (/*CONSTCOND*/ 0)
3017
3018#define CHECK_RRL_RATE(rate, def, max_rate, name) \
3019 do { \
3020 obj = NULL; \
3021 rrl->rate.str = name; \
3022 result = cfg_map_get(map, name, &obj); \
3023 if (result == ISC_R_SUCCESS) { \
3024 rrl->rate.r = cfg_obj_asuint32(obj); \
3025 CHECK_RRL(rrl->rate.r <= max_rate, \
3026 name" %d > %d", \
3027 rrl->rate.r, max_rate); \
3028 } else { \
3029 rrl->rate.r = def; \
3030 } \
3031 rrl->rate.scaled = rrl->rate.r; \
3032 } while (/*CONSTCOND*/0)
3033
3034static isc_result_t
3035configure_rrl(dns_view_t *view, const cfg_obj_t *config, const cfg_obj_t *map) {
3036 const cfg_obj_t *obj;
3037 dns_rrl_t *rrl;
3038 isc_result_t result;
3039 int min_entries, i, j;
3040
3041 /*
3042 * Most DNS servers have few clients, but intentinally open
3043 * recursive and authoritative servers often have many.
3044 * So start with a small number of entries unless told otherwise
3045 * to reduce cold-start costs.
3046 */
3047 min_entries = 500;
3048 obj = NULL;
3049 result = cfg_map_get(map, "min-table-size", &obj);
3050 if (result == ISC_R_SUCCESS) {
3051 min_entries = cfg_obj_asuint32(obj);
3052 if (min_entries < 1)
3053 min_entries = 1;
3054 }
3055 result = dns_rrl_init(&rrl, view, min_entries);
3056 if (result != ISC_R_SUCCESS)
3057 return (result);
3058
3059 i = ISC_MAX(20000, min_entries);
3060 obj = NULL;
3061 result = cfg_map_get(map, "max-table-size", &obj);
3062 if (result == ISC_R_SUCCESS) {
3063 i = cfg_obj_asuint32(obj);
3064 CHECK_RRL(i >= min_entries,
3065 "max-table-size %d < min-table-size %d",
3066 i, min_entries);
3067 }
3068 rrl->max_entries = i;
3069
3070 CHECK_RRL_RATE(responses_per_second, 0, DNS_RRL_MAX_RATE,
3071 "responses-per-second");
3072 CHECK_RRL_RATE(referrals_per_second,
3073 rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
3074 "referrals-per-second");
3075 CHECK_RRL_RATE(nodata_per_second,
3076 rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
3077 "nodata-per-second");
3078 CHECK_RRL_RATE(nxdomains_per_second,
3079 rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
3080 "nxdomains-per-second");
3081 CHECK_RRL_RATE(errors_per_second,
3082 rrl->responses_per_second.r, DNS_RRL_MAX_RATE,
3083 "errors-per-second");
3084
3085 CHECK_RRL_RATE(all_per_second, 0, DNS_RRL_MAX_RATE,
3086 "all-per-second");
3087
3088 CHECK_RRL_RATE(slip, 2, DNS_RRL_MAX_SLIP,
3089 "slip");
3090
3091 i = 15;
3092 obj = NULL;
3093 result = cfg_map_get(map, "window", &obj);
3094 if (result == ISC_R_SUCCESS) {
3095 i = cfg_obj_asuint32(obj);
3096 CHECK_RRL(i >= 1 && i <= DNS_RRL_MAX_WINDOW,
3097 "window %d < 1 or > %d", i, DNS_RRL_MAX_WINDOW);
3098 }
3099 rrl->window = i;
3100
3101 i = 0;
3102 obj = NULL;
3103 result = cfg_map_get(map, "qps-scale", &obj);
3104 if (result == ISC_R_SUCCESS) {
3105 i = cfg_obj_asuint32(obj);
3106 CHECK_RRL(i >= 1, "invalid 'qps-scale %d'%s", i, "");
3107 }
3108 rrl->qps_scale = i;
3109 rrl->qps = 1.0;
3110
3111 i = 24;
3112 obj = NULL;
3113 result = cfg_map_get(map, "ipv4-prefix-length", &obj);
3114 if (result == ISC_R_SUCCESS) {
3115 i = cfg_obj_asuint32(obj);
3116 CHECK_RRL(i >= 8 && i <= 32,
3117 "invalid 'ipv4-prefix-length %d'%s", i, "");
3118 }
3119 rrl->ipv4_prefixlen = i;
3120 if (i == 32)
3121 rrl->ipv4_mask = 0xffffffff;
3122 else
3123 rrl->ipv4_mask = htonl(0xffffffff << (32-i));
3124
3125 i = 56;
3126 obj = NULL;
3127 result = cfg_map_get(map, "ipv6-prefix-length", &obj);
3128 if (result == ISC_R_SUCCESS) {
3129 i = cfg_obj_asuint32(obj);
3130 CHECK_RRL(i >= 16 && i <= DNS_RRL_MAX_PREFIX,
3131 "ipv6-prefix-length %d < 16 or > %d",
3132 i, DNS_RRL_MAX_PREFIX);
3133 }
3134 rrl->ipv6_prefixlen = i;
3135 for (j = 0; j < 4; ++j) {
3136 if (i <= 0) {
3137 rrl->ipv6_mask[j] = 0;
3138 } else if (i < 32) {
3139 rrl->ipv6_mask[j] = htonl(0xffffffff << (32-i));
3140 } else {
3141 rrl->ipv6_mask[j] = 0xffffffff;
3142 }
3143 i -= 32;
3144 }
3145
3146 obj = NULL;
3147 result = cfg_map_get(map, "exempt-clients", &obj);
3148 if (result == ISC_R_SUCCESS) {
3149 result = cfg_acl_fromconfig(obj, config, named_g_lctx,
3150 named_g_aclconfctx, named_g_mctx,
3151 0, &rrl->exempt);
3152 CHECK_RRL(result == ISC_R_SUCCESS,
3153 "invalid %s%s", "address match list", "");
3154 }
3155
3156 obj = NULL;
3157 result = cfg_map_get(map, "log-only", &obj);
3158 if (result == ISC_R_SUCCESS && cfg_obj_asboolean(obj))
3159 rrl->log_only = true;
3160 else
3161 rrl->log_only = false;
3162
3163 return (ISC_R_SUCCESS);
3164
3165 cleanup:
3166 dns_rrl_view_destroy(view);
3167 return (result);
3168}
3169
3170static isc_result_t
3171add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3172 const dns_name_t *origin, const dns_name_t *contact)
3173{
3174 dns_dbnode_t *node = NULL;
3175 dns_rdata_t rdata = DNS_RDATA_INIT;
3176 dns_rdatalist_t rdatalist;
3177 dns_rdataset_t rdataset;
3178 isc_result_t result;
3179 unsigned char buf[DNS_SOA_BUFFERSIZE];
3180
3181 CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db),
3182 0, 28800, 7200, 604800, 86400, buf, &rdata));
3183
3184 dns_rdatalist_init(&rdatalist);
3185 rdatalist.type = rdata.type;
3186 rdatalist.rdclass = rdata.rdclass;
3187 rdatalist.ttl = 86400;
3188 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3189
3190 dns_rdataset_init(&rdataset);
3191 CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3192 CHECK(dns_db_findnode(db, name, true, &node));
3193 CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3194
3195 cleanup:
3196 if (node != NULL)
3197 dns_db_detachnode(db, &node);
3198 return (result);
3199}
3200
3201static isc_result_t
3202add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
3203 const dns_name_t *nsname)
3204{
3205 dns_dbnode_t *node = NULL;
3206 dns_rdata_ns_t ns;
3207 dns_rdata_t rdata = DNS_RDATA_INIT;
3208 dns_rdatalist_t rdatalist;
3209 dns_rdataset_t rdataset;
3210 isc_result_t result;
3211 isc_buffer_t b;
3212 unsigned char buf[DNS_NAME_MAXWIRE];
3213
3214 isc_buffer_init(&b, buf, sizeof(buf));
3215
3216 ns.common.rdtype = dns_rdatatype_ns;
3217 ns.common.rdclass = dns_db_class(db);
3218 ns.mctx = NULL;
3219 dns_name_init(&ns.name, NULL);
3220 dns_name_clone(nsname, &ns.name);
3221 CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
3222 &ns, &b));
3223
3224 dns_rdatalist_init(&rdatalist);
3225 rdatalist.type = rdata.type;
3226 rdatalist.rdclass = rdata.rdclass;
3227 rdatalist.ttl = 86400;
3228 ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
3229
3230 dns_rdataset_init(&rdataset);
3231 CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
3232 CHECK(dns_db_findnode(db, name, true, &node));
3233 CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
3234
3235 cleanup:
3236 if (node != NULL)
3237 dns_db_detachnode(db, &node);
3238 return (result);
3239}
3240
3241static isc_result_t
3242create_empty_zone(dns_zone_t *zone, dns_name_t *name, dns_view_t *view,
3243 const cfg_obj_t *zonelist, const char **empty_dbtype,
3244 int empty_dbtypec, dns_zonestat_level_t statlevel)
3245{
3246 char namebuf[DNS_NAME_FORMATSIZE];
3247 const cfg_listelt_t *element;
3248 const cfg_obj_t *obj;
3249 const cfg_obj_t *zconfig;
3250 const cfg_obj_t *zoptions;
3251 const char *rbt_dbtype[4] = { "rbt" };
3252 const char *sep = ": view ";
3253 const char *str;
3254 const char *viewname = view->name;
3255 dns_db_t *db = NULL;
3256 dns_dbversion_t *version = NULL;
3257 dns_fixedname_t cfixed;
3258 dns_fixedname_t fixed;
3259 dns_fixedname_t nsfixed;
3260 dns_name_t *contact;
3261 dns_name_t *ns;
3262 dns_name_t *zname;
3263 dns_zone_t *myzone = NULL;
3264 int rbt_dbtypec = 1;
3265 isc_result_t result;
3266 dns_namereln_t namereln;
3267 int order;
3268 unsigned int nlabels;
3269
3270 zname = dns_fixedname_initname(&fixed);
3271 ns = dns_fixedname_initname(&nsfixed);
3272 contact = dns_fixedname_initname(&cfixed);
3273
3274 /*
3275 * Look for forward "zones" beneath this empty zone and if so
3276 * create a custom db for the empty zone.
3277 */
3278 for (element = cfg_list_first(zonelist);
3279 element != NULL;
3280 element = cfg_list_next(element)) {
3281
3282 zconfig = cfg_listelt_value(element);
3283 str = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
3284 CHECK(dns_name_fromstring(zname, str, 0, NULL));
3285 namereln = dns_name_fullcompare(zname, name, &order, &nlabels);
3286 if (namereln != dns_namereln_subdomain)
3287 continue;
3288
3289 zoptions = cfg_tuple_get(zconfig, "options");
3290
3291 obj = NULL;
3292 (void)cfg_map_get(zoptions, "type", &obj);
3293 if (obj != NULL &&
3294 strcasecmp(cfg_obj_asstring(obj), "forward") == 0) {
3295 obj = NULL;
3296 (void)cfg_map_get(zoptions, "forward", &obj);
3297 if (obj == NULL)
3298 continue;
3299 if (strcasecmp(cfg_obj_asstring(obj), "only") != 0)
3300 continue;
3301 }
3302 if (db == NULL) {
3303 CHECK(dns_db_create(view->mctx, "rbt", name,
3304 dns_dbtype_zone, view->rdclass,
3305 0, NULL, &db));
3306 CHECK(dns_db_newversion(db, &version));
3307 if (strcmp(empty_dbtype[2], "@") == 0)
3308 dns_name_clone(name, ns);
3309 else
3310 CHECK(dns_name_fromstring(ns, empty_dbtype[2],
3311 0, NULL));
3312 CHECK(dns_name_fromstring(contact, empty_dbtype[3],
3313 0, NULL));
3314 CHECK(add_soa(db, version, name, ns, contact));
3315 CHECK(add_ns(db, version, name, ns));
3316 }
3317 CHECK(add_ns(db, version, zname, dns_rootname));
3318 }
3319
3320 /*
3321 * Is the existing zone the ok to use?
3322 */
3323 if (zone != NULL) {
3324 unsigned int typec;
3325 const char **dbargv;
3326
3327 if (db != NULL) {
3328 typec = rbt_dbtypec;
3329 dbargv = rbt_dbtype;
3330 } else {
3331 typec = empty_dbtypec;
3332 dbargv = empty_dbtype;
3333 }
3334
3335 result = check_dbtype(zone, typec, dbargv, view->mctx);
3336 if (result != ISC_R_SUCCESS)
3337 zone = NULL;
3338
3339 if (zone != NULL && dns_zone_gettype(zone) != dns_zone_master)
3340 zone = NULL;
3341 if (zone != NULL && dns_zone_getfile(zone) != NULL)
3342 zone = NULL;
3343 if (zone != NULL) {
3344 dns_zone_getraw(zone, &myzone);
3345 if (myzone != NULL) {
3346 dns_zone_detach(&myzone);
3347 zone = NULL;
3348 }
3349 }
3350 }
3351
3352 if (zone == NULL) {
3353 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &myzone));
3354 zone = myzone;
3355 CHECK(dns_zone_setorigin(zone, name));
3356 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
3357 if (db == NULL)
3358 CHECK(dns_zone_setdbtype(zone, empty_dbtypec,
3359 empty_dbtype));
3360 dns_zone_setclass(zone, view->rdclass);
3361 dns_zone_settype(zone, dns_zone_master);
3362 dns_zone_setstats(zone, named_g_server->zonestats);
3363 }
3364
3365 dns_zone_setoption(zone, ~DNS_ZONEOPT_NOCHECKNS, false);
3366 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
3367 dns_zone_setnotifytype(zone, dns_notifytype_no);
3368 dns_zone_setdialup(zone, dns_dialuptype_no);
3369 dns_zone_setautomatic(zone, true);
3370 if (view->queryacl != NULL)
3371 dns_zone_setqueryacl(zone, view->queryacl);
3372 else
3373 dns_zone_clearqueryacl(zone);
3374 if (view->queryonacl != NULL)
3375 dns_zone_setqueryonacl(zone, view->queryonacl);
3376 else
3377 dns_zone_clearqueryonacl(zone);
3378 dns_zone_clearupdateacl(zone);
3379 if (view->transferacl != NULL)
3380 dns_zone_setxfracl(zone, view->transferacl);
3381 else
3382 dns_zone_clearxfracl(zone);
3383
3384 CHECK(setquerystats(zone, view->mctx, statlevel));
3385 if (db != NULL) {
3386 dns_db_closeversion(db, &version, true);
3387 CHECK(dns_zone_replacedb(zone, db, false));
3388 }
3389 dns_zone_setoption(zone, DNS_ZONEOPT_AUTOEMPTY, true);
3390 dns_zone_setview(zone, view);
3391 CHECK(dns_view_addzone(view, zone));
3392
3393 if (!strcmp(viewname, "_default")) {
3394 sep = "";
3395 viewname = "";
3396 }
3397 dns_name_format(name, namebuf, sizeof(namebuf));
3398 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_ZONELOAD,
3399 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
3400 "automatic empty zone%s%s: %s",
3401 sep, viewname, namebuf);
3402
3403 cleanup:
3404 if (myzone != NULL)
3405 dns_zone_detach(&myzone);
3406 if (version != NULL)
3407 dns_db_closeversion(db, &version, false);
3408 if (db != NULL)
3409 dns_db_detach(&db);
3410
3411 INSIST(version == NULL);
3412
3413 return (result);
3414}
3415
3416#ifdef HAVE_DNSTAP
3417static isc_result_t
3418configure_dnstap(const cfg_obj_t **maps, dns_view_t *view) {
3419 isc_result_t result;
3420 const cfg_obj_t *obj, *obj2;
3421 const cfg_listelt_t *element;
3422 const char *dpath = named_g_defaultdnstap;
3423 const cfg_obj_t *dlist = NULL;
3424 dns_dtmsgtype_t dttypes = 0;
3425 unsigned int i;
3426 struct fstrm_iothr_options *fopt = NULL;
3427
3428 result = named_config_get(maps, "dnstap", &dlist);
3429 if (result != ISC_R_SUCCESS)
3430 return (ISC_R_SUCCESS);
3431
3432 for (element = cfg_list_first(dlist);
3433 element != NULL;
3434 element = cfg_list_next(element))
3435 {
3436 const char *str;
3437 dns_dtmsgtype_t dt = 0;
3438
3439 obj = cfg_listelt_value(element);
3440 obj2 = cfg_tuple_get(obj, "type");
3441 str = cfg_obj_asstring(obj2);
3442 if (strcasecmp(str, "client") == 0) {
3443 dt |= DNS_DTTYPE_CQ|DNS_DTTYPE_CR;
3444 } else if (strcasecmp(str, "auth") == 0) {
3445 dt |= DNS_DTTYPE_AQ|DNS_DTTYPE_AR;
3446 } else if (strcasecmp(str, "resolver") == 0) {
3447 dt |= DNS_DTTYPE_RQ|DNS_DTTYPE_RR;
3448 } else if (strcasecmp(str, "forwarder") == 0) {
3449 dt |= DNS_DTTYPE_FQ|DNS_DTTYPE_FR;
3450 } else if (strcasecmp(str, "update") == 0) {
3451 dt |= DNS_DTTYPE_UQ|DNS_DTTYPE_UR;
3452 } else if (strcasecmp(str, "all") == 0) {
3453 dt |= DNS_DTTYPE_CQ|DNS_DTTYPE_CR|
3454 DNS_DTTYPE_AQ|DNS_DTTYPE_AR|
3455 DNS_DTTYPE_RQ|DNS_DTTYPE_RR|
3456 DNS_DTTYPE_FQ|DNS_DTTYPE_FR|
3457 DNS_DTTYPE_UQ|DNS_DTTYPE_UR;
3458 }
3459
3460 obj2 = cfg_tuple_get(obj, "mode");
3461 if (obj2 == NULL || cfg_obj_isvoid(obj2)) {
3462 dttypes |= dt;
3463 continue;
3464 }
3465
3466 str = cfg_obj_asstring(obj2);
3467 if (strcasecmp(str, "query") == 0) {
3468 dt &= ~DNS_DTTYPE_RESPONSE;
3469 } else if (strcasecmp(str, "response") == 0) {
3470 dt &= ~DNS_DTTYPE_QUERY;
3471 }
3472
3473 dttypes |= dt;
3474 }
3475
3476 if (named_g_server->dtenv == NULL && dttypes != 0) {
3477 dns_dtmode_t dmode;
3478 uint64_t max_size = 0;
3479 uint32_t rolls = 0;
3480 isc_log_rollsuffix_t suffix = isc_log_rollsuffix_increment;
3481
3482 obj = NULL;
3483 CHECKM(named_config_get(maps, "dnstap-output", &obj),
3484 "'dnstap-output' must be set if 'dnstap' is set");
3485
3486 obj2 = cfg_tuple_get(obj, "mode");
3487 if (obj2 == NULL)
3488 CHECKM(ISC_R_FAILURE, "dnstap-output mode not found");
3489 if (strcasecmp(cfg_obj_asstring(obj2), "file") == 0)
3490 dmode = dns_dtmode_file;
3491 else
3492 dmode = dns_dtmode_unix;
3493
3494 obj2 = cfg_tuple_get(obj, "path");
3495 if (obj2 == NULL)
3496 CHECKM(ISC_R_FAILURE, "dnstap-output path not found");
3497
3498 dpath = cfg_obj_asstring(obj2);
3499
3500 obj2 = cfg_tuple_get(obj, "size");
3501 if (obj2 != NULL && cfg_obj_isuint64(obj2)) {
3502 max_size = cfg_obj_asuint64(obj2);
3503 if (max_size > SIZE_MAX) {
3504 cfg_obj_log(obj2, named_g_lctx,
3505 ISC_LOG_WARNING,
3506 "'dnstap-output size "
3507 "%" PRIu64 "' "
3508 "is too large for this "
3509 "system; reducing to %lu",
3510 max_size, (unsigned long)SIZE_MAX);
3511 max_size = SIZE_MAX;
3512 }
3513 }
3514
3515 obj2 = cfg_tuple_get(obj, "versions");
3516 if (obj2 != NULL && cfg_obj_isuint32(obj2)) {
3517 rolls = cfg_obj_asuint32(obj2);
3518 } else {
3519 rolls = ISC_LOG_ROLLINFINITE;
3520 }
3521
3522 obj2 = cfg_tuple_get(obj, "suffix");
3523 if (obj2 != NULL && cfg_obj_isstring(obj2) &&
3524 strcasecmp(cfg_obj_asstring(obj2), "timestamp") == 0)
3525 {
3526 suffix = isc_log_rollsuffix_timestamp;
3527 }
3528
3529 fopt = fstrm_iothr_options_init();
3530 fstrm_iothr_options_set_num_input_queues(fopt, named_g_cpus);
3531 fstrm_iothr_options_set_queue_model(fopt,
3532 FSTRM_IOTHR_QUEUE_MODEL_MPSC);
3533
3534 obj = NULL;
3535 result = named_config_get(maps, "fstrm-set-buffer-hint", &obj);
3536 if (result == ISC_R_SUCCESS) {
3537 i = cfg_obj_asuint32(obj);
3538 fstrm_iothr_options_set_buffer_hint(fopt, i);
3539 }
3540
3541 obj = NULL;
3542 result = named_config_get(maps, "fstrm-set-flush-timeout",
3543 &obj);
3544 if (result == ISC_R_SUCCESS) {
3545 i = cfg_obj_asuint32(obj);
3546 fstrm_iothr_options_set_flush_timeout(fopt, i);
3547 }
3548
3549 obj = NULL;
3550 result = named_config_get(maps, "fstrm-set-input-queue-size",
3551 &obj);
3552 if (result == ISC_R_SUCCESS) {
3553 i = cfg_obj_asuint32(obj);
3554 fstrm_iothr_options_set_input_queue_size(fopt, i);
3555 }
3556
3557 obj = NULL;
3558 result = named_config_get(maps,
3559 "fstrm-set-output-notify-threshold",
3560 &obj);
3561 if (result == ISC_R_SUCCESS) {
3562 i = cfg_obj_asuint32(obj);
3563 fstrm_iothr_options_set_queue_notify_threshold(fopt,
3564 i);
3565 }
3566
3567 obj = NULL;
3568 result = named_config_get(maps, "fstrm-set-output-queue-model",
3569 &obj);
3570 if (result == ISC_R_SUCCESS) {
3571 if (strcasecmp(cfg_obj_asstring(obj), "spsc") == 0)
3572 i = FSTRM_IOTHR_QUEUE_MODEL_SPSC;
3573 else
3574 i = FSTRM_IOTHR_QUEUE_MODEL_MPSC;
3575 fstrm_iothr_options_set_queue_model(fopt, i);
3576 }
3577
3578 obj = NULL;
3579 result = named_config_get(maps, "fstrm-set-output-queue-size",
3580 &obj);
3581 if (result == ISC_R_SUCCESS) {
3582 i = cfg_obj_asuint32(obj);
3583 fstrm_iothr_options_set_output_queue_size(fopt, i);
3584 }
3585
3586 obj = NULL;
3587 result = named_config_get(maps, "fstrm-set-reopen-interval",
3588 &obj);
3589 if (result == ISC_R_SUCCESS) {
3590 i = cfg_obj_asuint32(obj);
3591 fstrm_iothr_options_set_reopen_interval(fopt, i);
3592 }
3593
3594 CHECKM(dns_dt_create(named_g_mctx, dmode, dpath,
3595 &fopt, named_g_server->task,
3596 &named_g_server->dtenv),
3597 "unable to create dnstap environment");
3598
3599 CHECKM(dns_dt_setupfile(named_g_server->dtenv,
3600 max_size, rolls, suffix),
3601 "unable to set up dnstap logfile");
3602 }
3603
3604 if (named_g_server->dtenv == NULL)
3605 return (ISC_R_SUCCESS);
3606
3607 obj = NULL;
3608 result = named_config_get(maps, "dnstap-version", &obj);
3609 if (result != ISC_R_SUCCESS) {
3610 /* not specified; use the product and version */
3611 dns_dt_setversion(named_g_server->dtenv, PRODUCT " " VERSION);
3612 } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3613 /* Quoted string */
3614 dns_dt_setversion(named_g_server->dtenv, cfg_obj_asstring(obj));
3615 }
3616
3617 obj = NULL;
3618 result = named_config_get(maps, "dnstap-identity", &obj);
3619 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
3620 /* "hostname" is interpreted as boolean true */
3621 char buf[256];
3622 result = named_os_gethostname(buf, sizeof(buf));
3623 if (result == ISC_R_SUCCESS)
3624 dns_dt_setidentity(named_g_server->dtenv, buf);
3625 } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
3626 /* Quoted string */
3627 dns_dt_setidentity(named_g_server->dtenv,
3628 cfg_obj_asstring(obj));
3629 }
3630
3631 dns_dt_attach(named_g_server->dtenv, &view->dtenv);
3632 view->dttypes = dttypes;
3633
3634 result = ISC_R_SUCCESS;
3635
3636 cleanup:
3637 if (fopt != NULL)
3638 fstrm_iothr_options_destroy(&fopt);
3639
3640 return (result);
3641}
3642#endif /* HAVE_DNSTAP */
3643
3644static isc_result_t
3645create_mapped_acl(void) {
3646 isc_result_t result;
3647 dns_acl_t *acl = NULL;
3648 struct in6_addr in6 = IN6ADDR_V4MAPPED_INIT;
3649 isc_netaddr_t addr;
3650
3651 isc_netaddr_fromin6(&addr, &in6);
3652
3653 result = dns_acl_create(named_g_mctx, 1, &acl);
3654 if (result != ISC_R_SUCCESS)
3655 return (result);
3656
3657 result = dns_iptable_addprefix(acl->iptable, &addr, 96, true);
3658 if (result == ISC_R_SUCCESS)
3659 dns_acl_attach(acl, &named_g_mapped);
3660 dns_acl_detach(&acl);
3661 return (result);
3662}
3663
3664#ifdef HAVE_DLOPEN
3665/*%
3666 * A callback for the cfg_pluginlist_foreach() call in configure_view() below.
3667 * If registering any plugin fails, registering subsequent ones is not
3668 * attempted.
3669 */
3670static isc_result_t
3671register_one_plugin(const cfg_obj_t *config, const cfg_obj_t *obj,
3672 const char *plugin_path, const char *parameters,
3673 void *callback_data)
3674{
3675 dns_view_t *view = callback_data;
3676 char full_path[PATH_MAX];
3677 isc_result_t result;
3678
3679 result = ns_plugin_expandpath(plugin_path,
3680 full_path, sizeof(full_path));
3681 if (result != ISC_R_SUCCESS) {
3682 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3683 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3684 "%s: plugin configuration failed: "
3685 "unable to get full plugin path: %s",
3686 plugin_path, isc_result_totext(result));
3687 return (result);
3688 }
3689
3690 result = ns_plugin_register(full_path, parameters, config,
3691 cfg_obj_file(obj), cfg_obj_line(obj),
3692 named_g_mctx, named_g_lctx,
3693 named_g_aclconfctx, view);
3694 if (result != ISC_R_SUCCESS) {
3695 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
3696 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
3697 "%s: plugin configuration failed: %s",
3698 full_path, isc_result_totext(result));
3699 }
3700
3701 return (result);
3702}
3703#endif
3704
3705/*
3706 * Configure 'view' according to 'vconfig', taking defaults from 'config'
3707 * where values are missing in 'vconfig'.
3708 *
3709 * When configuring the default view, 'vconfig' will be NULL and the
3710 * global defaults in 'config' used exclusively.
3711 */
3712static isc_result_t
3713configure_view(dns_view_t *view, dns_viewlist_t *viewlist,
3714 cfg_obj_t *config, cfg_obj_t *vconfig,
3715 named_cachelist_t *cachelist, const cfg_obj_t *bindkeys,
3716 isc_mem_t *mctx, cfg_aclconfctx_t *actx,
3717 bool need_hints)
3718{
3719 const cfg_obj_t *maps[4];
3720 const cfg_obj_t *cfgmaps[3];
3721 const cfg_obj_t *optionmaps[3];
3722 const cfg_obj_t *options = NULL;
3723 const cfg_obj_t *voptions = NULL;
3724 const cfg_obj_t *forwardtype;
3725 const cfg_obj_t *forwarders;
3726 const cfg_obj_t *alternates;
3727 const cfg_obj_t *zonelist;
3728 const cfg_obj_t *dlzlist;
3729 const cfg_obj_t *dlz;
3730 const cfg_obj_t *dlvobj = NULL;
3731 unsigned int dlzargc;
3732 char **dlzargv;
3733 const cfg_obj_t *dyndb_list, *plugin_list;
3734 const cfg_obj_t *disabled;
3735 const cfg_obj_t *obj, *obj2;
3736 const cfg_listelt_t *element;
3737 in_port_t port;
3738 dns_cache_t *cache = NULL;
3739 isc_result_t result;
3740 unsigned int cleaning_interval;
3741 size_t max_cache_size;
3742 uint32_t max_cache_size_percent = 0;
3743 size_t max_adb_size;
3744 uint32_t lame_ttl, fail_ttl;
3745 uint32_t max_stale_ttl;
3746 dns_tsig_keyring_t *ring = NULL;
3747 dns_view_t *pview = NULL; /* Production view */
3748 isc_mem_t *cmctx = NULL, *hmctx = NULL;
3749 dns_dispatch_t *dispatch4 = NULL;
3750 dns_dispatch_t *dispatch6 = NULL;
3751 bool reused_cache = false;
3752 bool shared_cache = false;
3753 int i = 0, j = 0, k = 0;
3754 const char *str;
3755 const char *cachename = NULL;
3756 dns_order_t *order = NULL;
3757 uint32_t udpsize;
3758 uint32_t maxbits;
3759 unsigned int resopts = 0;
3760 dns_zone_t *zone = NULL;
3761 uint32_t max_clients_per_query;
3762 bool empty_zones_enable;
3763 const cfg_obj_t *disablelist = NULL;
3764 isc_stats_t *resstats = NULL;
3765 dns_stats_t *resquerystats = NULL;
3766 bool auto_root = false;
3767 named_cache_t *nsc;
3768 bool zero_no_soattl;
3769 dns_acl_t *clients = NULL, *mapped = NULL, *excluded = NULL;
3770 unsigned int query_timeout, ndisp;
3771 bool old_rpz_ok = false;
3772 isc_dscp_t dscp4 = -1, dscp6 = -1;
3773 dns_dyndbctx_t *dctx = NULL;
3774 unsigned int resolver_param;
3775 dns_ntatable_t *ntatable = NULL;
3776 const char *qminmode = NULL;
3777
3778 REQUIRE(DNS_VIEW_VALID(view));
3779
3780 if (config != NULL)
3781 (void)cfg_map_get(config, "options", &options);
3782
3783 /*
3784 * maps: view options, options, defaults
3785 * cfgmaps: view options, config
3786 * optionmaps: view options, options
3787 */
3788 if (vconfig != NULL) {
3789 voptions = cfg_tuple_get(vconfig, "options");
3790 maps[i++] = voptions;
3791 optionmaps[j++] = voptions;
3792 cfgmaps[k++] = voptions;
3793 }
3794 if (options != NULL) {
3795 maps[i++] = options;
3796 optionmaps[j++] = options;
3797 }
3798
3799 maps[i++] = named_g_defaults;
3800 maps[i] = NULL;
3801 optionmaps[j] = NULL;
3802 if (config != NULL)
3803 cfgmaps[k++] = config;
3804 cfgmaps[k] = NULL;
3805
3806 /*
3807 * Set the view's port number for outgoing queries.
3808 */
3809 CHECKM(named_config_getport(config, &port), "port");
3810 dns_view_setdstport(view, port);
3811
3812 /*
3813 * Make the list of response policy zone names for a view that
3814 * is used for real lookups and so cares about hints.
3815 */
3816 obj = NULL;
3817 if (view->rdclass == dns_rdataclass_in && need_hints &&
3818 named_config_get(maps, "response-policy", &obj) == ISC_R_SUCCESS) {
3819 CHECK(configure_rpz(view, maps, obj, &old_rpz_ok));
3820 }
3821
3822 obj = NULL;
3823 if (view->rdclass == dns_rdataclass_in && need_hints &&
3824 named_config_get(maps, "catalog-zones", &obj) == ISC_R_SUCCESS) {
3825 CHECK(configure_catz(view, config, obj));
3826 }
3827
3828 /*
3829 * Configure the zones.
3830 */
3831 zonelist = NULL;
3832 if (voptions != NULL)
3833 (void)cfg_map_get(voptions, "zone", &zonelist);
3834 else
3835 (void)cfg_map_get(config, "zone", &zonelist);
3836
3837 /*
3838 * Load zone configuration
3839 */
3840 for (element = cfg_list_first(zonelist);
3841 element != NULL;
3842 element = cfg_list_next(element))
3843 {
3844 const cfg_obj_t *zconfig = cfg_listelt_value(element);
3845 CHECK(configure_zone(config, zconfig, vconfig, mctx, view,
3846 viewlist, actx, false, old_rpz_ok,
3847 false));
3848 }
3849
3850 /*
3851 * Check that a master or slave zone was found for each
3852 * zone named in the response policy statement
3853 * unless we are using RPZ service interface.
3854 */
3855 if (view->rpzs != NULL && !view->rpzs->p.dnsrps_enabled) {
3856 dns_rpz_num_t n;
3857
3858 for (n = 0; n < view->rpzs->p.num_zones; ++n) {
3859 if ((view->rpzs->defined & DNS_RPZ_ZBIT(n)) == 0) {
3860 char namebuf[DNS_NAME_FORMATSIZE];
3861
3862 dns_name_format(&view->rpzs->zones[n]->origin,
3863 namebuf, sizeof(namebuf));
3864 isc_log_write(named_g_lctx,
3865 NAMED_LOGCATEGORY_GENERAL,
3866 NAMED_LOGMODULE_SERVER,
3867 DNS_RPZ_ERROR_LEVEL, "rpz '%s'"
3868 " is not a master or slave zone",
3869 namebuf);
3870 result = ISC_R_NOTFOUND;
3871 goto cleanup;
3872 }
3873 }
3874 }
3875
3876 /*
3877 * If we're allowing added zones, then load zone configuration
3878 * from the newzone file for zones that were added during previous
3879 * runs.
3880 */
3881 CHECK(configure_newzones(view, config, vconfig, mctx, actx));
3882
3883 /*
3884 * Create Dynamically Loadable Zone driver.
3885 */
3886 dlzlist = NULL;
3887 if (voptions != NULL)
3888 (void)cfg_map_get(voptions, "dlz", &dlzlist);
3889 else
3890 (void)cfg_map_get(config, "dlz", &dlzlist);
3891
3892 for (element = cfg_list_first(dlzlist);
3893 element != NULL;
3894 element = cfg_list_next(element))
3895 {
3896 dlz = cfg_listelt_value(element);
3897
3898 obj = NULL;
3899 (void)cfg_map_get(dlz, "database", &obj);
3900 if (obj != NULL) {
3901 dns_dlzdb_t *dlzdb = NULL;
3902 const cfg_obj_t *name, *search = NULL;
3903 char *s = isc_mem_strdup(mctx, cfg_obj_asstring(obj));
3904
3905 if (s == NULL) {
3906 result = ISC_R_NOMEMORY;
3907 goto cleanup;
3908 }
3909
3910 result = isc_commandline_strtoargv(mctx, s, &dlzargc,
3911 &dlzargv, 0);
3912 if (result != ISC_R_SUCCESS) {
3913 isc_mem_free(mctx, s);
3914 goto cleanup;
3915 }
3916
3917 name = cfg_map_getname(dlz);
3918 result = dns_dlzcreate(mctx, cfg_obj_asstring(name),
3919 dlzargv[0], dlzargc, dlzargv,
3920 &dlzdb);
3921 isc_mem_free(mctx, s);
3922 isc_mem_put(mctx, dlzargv, dlzargc * sizeof(*dlzargv));
3923 if (result != ISC_R_SUCCESS)
3924 goto cleanup;
3925
3926 /*
3927 * If the DLZ backend supports configuration,
3928 * and is searchable, then call its configure
3929 * method now. If not searchable, we'll take
3930 * care of it when we process the zone statement.
3931 */
3932 (void)cfg_map_get(dlz, "search", &search);
3933 if (search == NULL || cfg_obj_asboolean(search)) {
3934 dlzdb->search = true;
3935 result = dns_dlzconfigure(view, dlzdb,
3936 dlzconfigure_callback);
3937 if (result != ISC_R_SUCCESS)
3938 goto cleanup;
3939 ISC_LIST_APPEND(view->dlz_searched,
3940 dlzdb, link);
3941 } else {
3942 dlzdb->search = false;
3943 ISC_LIST_APPEND(view->dlz_unsearched,
3944 dlzdb, link);
3945 }
3946
3947 }
3948 }
3949
3950 /*
3951 * Obtain configuration parameters that affect the decision of whether
3952 * we can reuse/share an existing cache.
3953 */
3954 obj = NULL;
3955 result = named_config_get(maps, "cleaning-interval", &obj);
3956 INSIST(result == ISC_R_SUCCESS);
3957 cleaning_interval = cfg_obj_asuint32(obj) * 60;
3958
3959 obj = NULL;
3960 result = named_config_get(maps, "max-cache-size", &obj);
3961 INSIST(result == ISC_R_SUCCESS);
3962 if (cfg_obj_isstring(obj)) {
3963 str = cfg_obj_asstring(obj);
3964 INSIST(strcasecmp(str, "unlimited") == 0);
3965 max_cache_size = 0;
3966 } else if (cfg_obj_ispercentage(obj)) {
3967 max_cache_size = SIZE_AS_PERCENT;
3968 max_cache_size_percent = cfg_obj_aspercentage(obj);
3969 } else {
3970 isc_resourcevalue_t value;
3971 value = cfg_obj_asuint64(obj);
3972 if (value > SIZE_MAX) {
3973 cfg_obj_log(obj, named_g_lctx,
3974 ISC_LOG_WARNING,
3975 "'max-cache-size "
3976 "%" PRIu64 "' "
3977 "is too large for this "
3978 "system; reducing to %lu",
3979 value, (unsigned long)SIZE_MAX);
3980 value = SIZE_MAX;
3981 }
3982 max_cache_size = (size_t) value;
3983 }
3984
3985 if (max_cache_size == SIZE_AS_PERCENT) {
3986 uint64_t totalphys = isc_meminfo_totalphys();
3987
3988 max_cache_size =
3989 (size_t) (totalphys * max_cache_size_percent/100);
3990 if (totalphys == 0) {
3991 cfg_obj_log(obj, named_g_lctx,
3992 ISC_LOG_WARNING,
3993 "Unable to determine amount of physical "
3994 "memory, setting 'max-cache-size' to "
3995 "unlimited");
3996 } else {
3997 cfg_obj_log(obj, named_g_lctx,
3998 ISC_LOG_INFO,
3999 "'max-cache-size %d%%' "
4000 "- setting to %" PRIu64 "MB "
4001 "(out of %" PRIu64 "MB)",
4002 max_cache_size_percent,
4003 (uint64_t)(max_cache_size / (1024*1024)),
4004 totalphys / (1024*1024));
4005 }
4006 }
4007
4008 /* Check-names. */
4009 obj = NULL;
4010 result = named_checknames_get(maps, "response", &obj);
4011 INSIST(result == ISC_R_SUCCESS);
4012
4013 str = cfg_obj_asstring(obj);
4014 if (strcasecmp(str, "fail") == 0) {
4015 resopts |= DNS_RESOLVER_CHECKNAMES |
4016 DNS_RESOLVER_CHECKNAMESFAIL;
4017 view->checknames = true;
4018 } else if (strcasecmp(str, "warn") == 0) {
4019 resopts |= DNS_RESOLVER_CHECKNAMES;
4020 view->checknames = false;
4021 } else if (strcasecmp(str, "ignore") == 0) {
4022 view->checknames = false;
4023 } else {
4024 INSIST(0);
4025 ISC_UNREACHABLE();
4026 }
4027
4028 obj = NULL;
4029 result = named_config_get(maps, "zero-no-soa-ttl-cache", &obj);
4030 INSIST(result == ISC_R_SUCCESS);
4031 zero_no_soattl = cfg_obj_asboolean(obj);
4032
4033 obj = NULL;
4034 result = named_config_get(maps, "dns64", &obj);
4035 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") &&
4036 strcmp(view->name, "_meta")) {
4037 isc_netaddr_t na, suffix, *sp;
4038 unsigned int prefixlen;
4039 const char *server, *contact;
4040 const cfg_obj_t *myobj;
4041
4042 myobj = NULL;
4043 result = named_config_get(maps, "dns64-server", &myobj);
4044 if (result == ISC_R_SUCCESS)
4045 server = cfg_obj_asstring(myobj);
4046 else
4047 server = NULL;
4048
4049 myobj = NULL;
4050 result = named_config_get(maps, "dns64-contact", &myobj);
4051 if (result == ISC_R_SUCCESS)
4052 contact = cfg_obj_asstring(myobj);
4053 else
4054 contact = NULL;
4055
4056 for (element = cfg_list_first(obj);
4057 element != NULL;
4058 element = cfg_list_next(element))
4059 {
4060 const cfg_obj_t *map = cfg_listelt_value(element);
4061 dns_dns64_t *dns64 = NULL;
4062 unsigned int dns64options = 0;
4063
4064 cfg_obj_asnetprefix(cfg_map_getname(map), &na,
4065 &prefixlen);
4066
4067 obj = NULL;
4068 (void)cfg_map_get(map, "suffix", &obj);
4069 if (obj != NULL) {
4070 sp = &suffix;
4071 isc_netaddr_fromsockaddr(sp,
4072 cfg_obj_assockaddr(obj));
4073 } else
4074 sp = NULL;
4075
4076 clients = mapped = excluded = NULL;
4077 obj = NULL;
4078 (void)cfg_map_get(map, "clients", &obj);
4079 if (obj != NULL) {
4080 result = cfg_acl_fromconfig(obj, config,
4081 named_g_lctx, actx,
4082 mctx, 0, &clients);
4083 if (result != ISC_R_SUCCESS)
4084 goto cleanup;
4085 }
4086 obj = NULL;
4087 (void)cfg_map_get(map, "mapped", &obj);
4088 if (obj != NULL) {
4089 result = cfg_acl_fromconfig(obj, config,
4090 named_g_lctx, actx,
4091 mctx, 0, &mapped);
4092 if (result != ISC_R_SUCCESS)
4093 goto cleanup;
4094 }
4095 obj = NULL;
4096 (void)cfg_map_get(map, "exclude", &obj);
4097 if (obj != NULL) {
4098 result = cfg_acl_fromconfig(obj, config,
4099 named_g_lctx, actx,
4100 mctx, 0, &excluded);
4101 if (result != ISC_R_SUCCESS)
4102 goto cleanup;
4103 } else {
4104 if (named_g_mapped == NULL) {
4105 result = create_mapped_acl();
4106 if (result != ISC_R_SUCCESS)
4107 goto cleanup;
4108 }
4109 dns_acl_attach(named_g_mapped, &excluded);
4110 }
4111
4112 obj = NULL;
4113 (void)cfg_map_get(map, "recursive-only", &obj);
4114 if (obj != NULL && cfg_obj_asboolean(obj))
4115 dns64options |= DNS_DNS64_RECURSIVE_ONLY;
4116
4117 obj = NULL;
4118 (void)cfg_map_get(map, "break-dnssec", &obj);
4119 if (obj != NULL && cfg_obj_asboolean(obj))
4120 dns64options |= DNS_DNS64_BREAK_DNSSEC;
4121
4122 result = dns_dns64_create(mctx, &na, prefixlen, sp,
4123 clients, mapped, excluded,
4124 dns64options, &dns64);
4125 if (result != ISC_R_SUCCESS)
4126 goto cleanup;
4127 dns_dns64_append(&view->dns64, dns64);
4128 view->dns64cnt++;
4129 result = dns64_reverse(view, mctx, &na, prefixlen,
4130 server, contact);
4131 if (result != ISC_R_SUCCESS)
4132 goto cleanup;
4133 if (clients != NULL)
4134 dns_acl_detach(&clients);
4135 if (mapped != NULL)
4136 dns_acl_detach(&mapped);
4137 if (excluded != NULL)
4138 dns_acl_detach(&excluded);
4139 }
4140 }
4141
4142 obj = NULL;
4143 result = named_config_get(maps, "dnssec-accept-expired", &obj);
4144 INSIST(result == ISC_R_SUCCESS);
4145 view->acceptexpired = cfg_obj_asboolean(obj);
4146
4147 obj = NULL;
4148 result = named_config_get(maps, "dnssec-enable", &obj);
4149 INSIST(result == ISC_R_SUCCESS);
4150 view->enablednssec = cfg_obj_asboolean(obj);
4151
4152 obj = NULL;
4153 /* 'optionmaps', not 'maps': don't check named_g_defaults yet */
4154 (void)named_config_get(optionmaps, "dnssec-validation", &obj);
4155 if (obj == NULL) {
4156 /*
4157 * If dnssec-enable is yes, then we default to
4158 * VALIDATION_DEFAULT as set in config.c. Otherwise
4159 * we default to "no".
4160 */
4161 if (view->enablednssec) {
4162 (void)cfg_map_get(named_g_defaults,
4163 "dnssec-validation", &obj);
4164 INSIST(obj != NULL);
4165 } else {
4166 view->enablevalidation = false;
4167 }
4168 }
4169 if (obj != NULL) {
4170 if (cfg_obj_isboolean(obj)) {
4171 view->enablevalidation = cfg_obj_asboolean(obj);
4172 } else {
4173 /*
4174 * If dnssec-validation is set but not boolean,
4175 * then it must be "auto"
4176 */
4177 view->enablevalidation = true;
4178 auto_root = true;
4179 }
4180 }
4181
4182 obj = NULL;
4183 result = named_config_get(maps, "max-cache-ttl", &obj);
4184 INSIST(result == ISC_R_SUCCESS);
4185 view->maxcachettl = cfg_obj_asuint32(obj);
4186
4187 obj = NULL;
4188 result = named_config_get(maps, "max-ncache-ttl", &obj);
4189 INSIST(result == ISC_R_SUCCESS);
4190 view->maxncachettl = cfg_obj_asuint32(obj);
4191
4192 obj = NULL;
4193 result = named_config_get(maps, "min-cache-ttl", &obj);
4194 INSIST(result == ISC_R_SUCCESS);
4195 view->mincachettl = cfg_obj_asuint32(obj);
4196
4197 obj = NULL;
4198 result = named_config_get(maps, "min-ncache-ttl", &obj);
4199 INSIST(result == ISC_R_SUCCESS);
4200 view->minncachettl = cfg_obj_asuint32(obj);
4201
4202 obj = NULL;
4203 result = named_config_get(maps, "synth-from-dnssec", &obj);
4204 INSIST(result == ISC_R_SUCCESS);
4205 view->synthfromdnssec = cfg_obj_asboolean(obj);
4206
4207 obj = NULL;
4208 result = named_config_get(maps, "max-stale-ttl", &obj);
4209 INSIST(result == ISC_R_SUCCESS);
4210 max_stale_ttl = ISC_MAX(cfg_obj_asuint32(obj), 1);
4211
4212 obj = NULL;
4213 result = named_config_get(maps, "stale-answer-enable", &obj);
4214 INSIST(result == ISC_R_SUCCESS);
4215 view->staleanswersenable = cfg_obj_asboolean(obj);
4216
4217 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4218 view->rdclass, &pview);
4219 if (result == ISC_R_SUCCESS) {
4220 view->staleanswersok = pview->staleanswersok;
4221 dns_view_detach(&pview);
4222 } else
4223 view->staleanswersok = dns_stale_answer_conf;
4224
4225 /*
4226 * Configure the view's cache.
4227 *
4228 * First, check to see if there are any attach-cache options. If yes,
4229 * attempt to lookup an existing cache at attach it to the view. If
4230 * there is not one, then try to reuse an existing cache if possible;
4231 * otherwise create a new cache.
4232 *
4233 * Note that the ADB is not preserved or shared in either case.
4234 *
4235 * When a matching view is found, the associated statistics are also
4236 * retrieved and reused.
4237 *
4238 * XXX Determining when it is safe to reuse or share a cache is tricky.
4239 * When the view's configuration changes, the cached data may become
4240 * invalid because it reflects our old view of the world. We check
4241 * some of the configuration parameters that could invalidate the cache
4242 * or otherwise make it unsharable, but there are other configuration
4243 * options that should be checked. For example, if a view uses a
4244 * forwarder, changes in the forwarder configuration may invalidate
4245 * the cache. At the moment, it's the administrator's responsibility to
4246 * ensure these configuration options don't invalidate reusing/sharing.
4247 */
4248 obj = NULL;
4249 result = named_config_get(maps, "attach-cache", &obj);
4250 if (result == ISC_R_SUCCESS)
4251 cachename = cfg_obj_asstring(obj);
4252 else
4253 cachename = view->name;
4254 cache = NULL;
4255 nsc = cachelist_find(cachelist, cachename, view->rdclass);
4256 if (nsc != NULL) {
4257 if (!cache_sharable(nsc->primaryview, view, zero_no_soattl,
4258 cleaning_interval, max_cache_size,
4259 max_stale_ttl))
4260 {
4261 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4262 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
4263 "views %s and %s can't share the cache "
4264 "due to configuration parameter mismatch",
4265 nsc->primaryview->name, view->name);
4266 result = ISC_R_FAILURE;
4267 goto cleanup;
4268 }
4269 dns_cache_attach(nsc->cache, &cache);
4270 shared_cache = true;
4271 } else {
4272 if (strcmp(cachename, view->name) == 0) {
4273 result = dns_viewlist_find(&named_g_server->viewlist,
4274 cachename, view->rdclass,
4275 &pview);
4276 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4277 goto cleanup;
4278 if (pview != NULL) {
4279 if (!cache_reusable(pview, view,
4280 zero_no_soattl)) {
4281 isc_log_write(named_g_lctx,
4282 NAMED_LOGCATEGORY_GENERAL,
4283 NAMED_LOGMODULE_SERVER,
4284 ISC_LOG_DEBUG(1),
4285 "cache cannot be reused "
4286 "for view %s due to "
4287 "configuration parameter "
4288 "mismatch", view->name);
4289 } else {
4290 INSIST(pview->cache != NULL);
4291 isc_log_write(named_g_lctx,
4292 NAMED_LOGCATEGORY_GENERAL,
4293 NAMED_LOGMODULE_SERVER,
4294 ISC_LOG_DEBUG(3),
4295 "reusing existing cache");
4296 reused_cache = true;
4297 dns_cache_attach(pview->cache, &cache);
4298 }
4299 dns_view_getresstats(pview, &resstats);
4300 dns_view_getresquerystats(pview,
4301 &resquerystats);
4302 dns_view_detach(&pview);
4303 }
4304 }
4305 if (cache == NULL) {
4306 /*
4307 * Create a cache with the desired name. This normally
4308 * equals the view name, but may also be a forward
4309 * reference to a view that share the cache with this
4310 * view but is not yet configured. If it is not the
4311 * view name but not a forward reference either, then it
4312 * is simply a named cache that is not shared.
4313 *
4314 * We use two separate memory contexts for the
4315 * cache, for the main cache memory and the heap
4316 * memory.
4317 */
4318 CHECK(isc_mem_create(0, 0, &cmctx));
4319 isc_mem_setname(cmctx, "cache", NULL);
4320 CHECK(isc_mem_create(0, 0, &hmctx));
4321 isc_mem_setname(hmctx, "cache_heap", NULL);
4322 CHECK(dns_cache_create(cmctx, hmctx, named_g_taskmgr,
4323 named_g_timermgr, view->rdclass,
4324 cachename, "rbt", 0, NULL,
4325 &cache));
4326 isc_mem_detach(&cmctx);
4327 isc_mem_detach(&hmctx);
4328 }
4329 nsc = isc_mem_get(mctx, sizeof(*nsc));
4330 if (nsc == NULL) {
4331 result = ISC_R_NOMEMORY;
4332 goto cleanup;
4333 }
4334 nsc->cache = NULL;
4335 dns_cache_attach(cache, &nsc->cache);
4336 nsc->primaryview = view;
4337 nsc->needflush = false;
4338 nsc->adbsizeadjusted = false;
4339 nsc->rdclass = view->rdclass;
4340 ISC_LINK_INIT(nsc, link);
4341 ISC_LIST_APPEND(*cachelist, nsc, link);
4342 }
4343 dns_view_setcache(view, cache, shared_cache);
4344
4345 /*
4346 * cache-file cannot be inherited if views are present, but this
4347 * should be caught by the configuration checking stage.
4348 */
4349 obj = NULL;
4350 result = named_config_get(maps, "cache-file", &obj);
4351 if (result == ISC_R_SUCCESS && strcmp(view->name, "_bind") != 0) {
4352 CHECK(dns_cache_setfilename(cache, cfg_obj_asstring(obj)));
4353 if (!reused_cache && !shared_cache)
4354 CHECK(dns_cache_load(cache));
4355 }
4356
4357 dns_cache_setcleaninginterval(cache, cleaning_interval);
4358 dns_cache_setcachesize(cache, max_cache_size);
4359 dns_cache_setservestalettl(cache, max_stale_ttl);
4360
4361 dns_cache_detach(&cache);
4362
4363 obj = NULL;
4364 result = named_config_get(maps, "stale-answer-ttl", &obj);
4365 INSIST(result == ISC_R_SUCCESS);
4366 view->staleanswerttl = ISC_MAX(cfg_obj_asuint32(obj), 1);
4367
4368 /*
4369 * Resolver.
4370 *
4371 * XXXRTH Hardwired number of tasks.
4372 */
4373 CHECK(get_view_querysource_dispatch(maps, AF_INET, &dispatch4, &dscp4,
4374 (ISC_LIST_PREV(view, link) == NULL)));
4375 CHECK(get_view_querysource_dispatch(maps, AF_INET6, &dispatch6, &dscp6,
4376 (ISC_LIST_PREV(view, link) == NULL)));
4377 if (dispatch4 == NULL && dispatch6 == NULL) {
4378 UNEXPECTED_ERROR(__FILE__, __LINE__,
4379 "unable to obtain neither an IPv4 nor"
4380 " an IPv6 dispatch");
4381 result = ISC_R_UNEXPECTED;
4382 goto cleanup;
4383 }
4384
4385 if (resstats == NULL) {
4386 CHECK(isc_stats_create(mctx, &resstats,
4387 dns_resstatscounter_max));
4388 }
4389 dns_view_setresstats(view, resstats);
4390 if (resquerystats == NULL)
4391 CHECK(dns_rdatatypestats_create(mctx, &resquerystats));
4392 dns_view_setresquerystats(view, resquerystats);
4393
4394 ndisp = 4 * ISC_MIN(named_g_udpdisp, MAX_UDP_DISPATCH);
4395 CHECK(dns_view_createresolver(view, named_g_taskmgr, RESOLVER_NTASKS,
4396 ndisp, named_g_socketmgr,
4397 named_g_timermgr, resopts,
4398 named_g_dispatchmgr,
4399 dispatch4, dispatch6));
4400
4401 if (dscp4 == -1)
4402 dscp4 = named_g_dscp;
4403 if (dscp6 == -1)
4404 dscp6 = named_g_dscp;
4405 if (dscp4 != -1)
4406 dns_resolver_setquerydscp4(view->resolver, dscp4);
4407 if (dscp6 != -1)
4408 dns_resolver_setquerydscp6(view->resolver, dscp6);
4409
4410 /*
4411 * Set the ADB cache size to 1/8th of the max-cache-size or
4412 * MAX_ADB_SIZE_FOR_CACHESHARE when the cache is shared.
4413 */
4414 max_adb_size = 0;
4415 if (max_cache_size != 0U) {
4416 max_adb_size = max_cache_size / 8;
4417 if (max_adb_size == 0U)
4418 max_adb_size = 1; /* Force minimum. */
4419 if (view != nsc->primaryview &&
4420 max_adb_size > MAX_ADB_SIZE_FOR_CACHESHARE) {
4421 max_adb_size = MAX_ADB_SIZE_FOR_CACHESHARE;
4422 if (!nsc->adbsizeadjusted) {
4423 dns_adb_setadbsize(nsc->primaryview->adb,
4424 MAX_ADB_SIZE_FOR_CACHESHARE);
4425 nsc->adbsizeadjusted = true;
4426 }
4427 }
4428 }
4429 dns_adb_setadbsize(view->adb, max_adb_size);
4430
4431 /*
4432 * Set up ADB quotas
4433 */
4434 {
4435 uint32_t fps, freq;
4436 double low, high, discount;
4437
4438 obj = NULL;
4439 result = named_config_get(maps, "fetches-per-server", &obj);
4440 INSIST(result == ISC_R_SUCCESS);
4441 obj2 = cfg_tuple_get(obj, "fetches");
4442 fps = cfg_obj_asuint32(obj2);
4443 obj2 = cfg_tuple_get(obj, "response");
4444 if (!cfg_obj_isvoid(obj2)) {
4445 const char *resp = cfg_obj_asstring(obj2);
4446 isc_result_t r = DNS_R_SERVFAIL;
4447
4448 if (strcasecmp(resp, "drop") == 0) {
4449 r = DNS_R_DROP;
4450 } else if (strcasecmp(resp, "fail") == 0) {
4451 r = DNS_R_SERVFAIL;
4452 } else {
4453 INSIST(0);
4454 ISC_UNREACHABLE();
4455 }
4456
4457 dns_resolver_setquotaresponse(view->resolver,
4458 dns_quotatype_server, r);
4459 }
4460
4461 obj = NULL;
4462 result = named_config_get(maps, "fetch-quota-params", &obj);
4463 INSIST(result == ISC_R_SUCCESS);
4464
4465 obj2 = cfg_tuple_get(obj, "frequency");
4466 freq = cfg_obj_asuint32(obj2);
4467
4468 obj2 = cfg_tuple_get(obj, "low");
4469 low = (double) cfg_obj_asfixedpoint(obj2) / 100.0;
4470
4471 obj2 = cfg_tuple_get(obj, "high");
4472 high = (double) cfg_obj_asfixedpoint(obj2) / 100.0;
4473
4474 obj2 = cfg_tuple_get(obj, "discount");
4475 discount = (double) cfg_obj_asfixedpoint(obj2) / 100.0;
4476
4477 dns_adb_setquota(view->adb, fps, freq, low, high, discount);
4478 }
4479
4480 /*
4481 * Set resolver's lame-ttl.
4482 */
4483 obj = NULL;
4484 result = named_config_get(maps, "lame-ttl", &obj);
4485 INSIST(result == ISC_R_SUCCESS);
4486 lame_ttl = cfg_obj_asuint32(obj);
4487 if (lame_ttl > 1800)
4488 lame_ttl = 1800;
4489 dns_resolver_setlamettl(view->resolver, lame_ttl);
4490
4491 /*
4492 * Set the resolver's query timeout.
4493 */
4494 obj = NULL;
4495 result = named_config_get(maps, "resolver-query-timeout", &obj);
4496 INSIST(result == ISC_R_SUCCESS);
4497 query_timeout = cfg_obj_asuint32(obj);
4498 dns_resolver_settimeout(view->resolver, query_timeout);
4499
4500 /* Specify whether to use 0-TTL for negative response for SOA query */
4501 dns_resolver_setzeronosoattl(view->resolver, zero_no_soattl);
4502
4503 /*
4504 * Set the resolver's EDNS UDP size.
4505 */
4506 obj = NULL;
4507 result = named_config_get(maps, "edns-udp-size", &obj);
4508 INSIST(result == ISC_R_SUCCESS);
4509 udpsize = cfg_obj_asuint32(obj);
4510 if (udpsize < 512)
4511 udpsize = 512;
4512 if (udpsize > 4096)
4513 udpsize = 4096;
4514 dns_resolver_setudpsize(view->resolver, (uint16_t)udpsize);
4515
4516 /*
4517 * Set the maximum UDP response size.
4518 */
4519 obj = NULL;
4520 result = named_config_get(maps, "max-udp-size", &obj);
4521 INSIST(result == ISC_R_SUCCESS);
4522 udpsize = cfg_obj_asuint32(obj);
4523 if (udpsize < 512)
4524 udpsize = 512;
4525 if (udpsize > 4096)
4526 udpsize = 4096;
4527 view->maxudp = udpsize;
4528
4529 /*
4530 * Set the maximum UDP when a COOKIE is not provided.
4531 */
4532 obj = NULL;
4533 result = named_config_get(maps, "nocookie-udp-size", &obj);
4534 INSIST(result == ISC_R_SUCCESS);
4535 udpsize = cfg_obj_asuint32(obj);
4536 if (udpsize < 128)
4537 udpsize = 128;
4538 if (udpsize > view->maxudp)
4539 udpsize = view->maxudp;
4540 view->nocookieudp = udpsize;
4541
4542 /*
4543 * Set the maximum rsa exponent bits.
4544 */
4545 obj = NULL;
4546 result = named_config_get(maps, "max-rsa-exponent-size", &obj);
4547 INSIST(result == ISC_R_SUCCESS);
4548 maxbits = cfg_obj_asuint32(obj);
4549 if (maxbits != 0 && maxbits < 35)
4550 maxbits = 35;
4551 if (maxbits > 4096)
4552 maxbits = 4096;
4553 view->maxbits = maxbits;
4554
4555 /*
4556 * Set resolver retry parameters.
4557 */
4558 obj = NULL;
4559 CHECK(named_config_get(maps, "resolver-retry-interval", &obj));
4560 resolver_param = cfg_obj_asuint32(obj);
4561 if (resolver_param > 0)
4562 dns_resolver_setretryinterval(view->resolver, resolver_param);
4563
4564 obj = NULL;
4565 CHECK(named_config_get(maps, "resolver-nonbackoff-tries", &obj));
4566 resolver_param = cfg_obj_asuint32(obj);
4567 if (resolver_param > 0)
4568 dns_resolver_setnonbackofftries(view->resolver, resolver_param);
4569
4570 /*
4571 * Set supported DNSSEC algorithms.
4572 */
4573 dns_resolver_reset_algorithms(view->resolver);
4574 disabled = NULL;
4575 (void)named_config_get(maps, "disable-algorithms", &disabled);
4576 if (disabled != NULL) {
4577 for (element = cfg_list_first(disabled);
4578 element != NULL;
4579 element = cfg_list_next(element))
4580 CHECK(disable_algorithms(cfg_listelt_value(element),
4581 view->resolver));
4582 }
4583
4584 /*
4585 * Set supported DS/DLV digest types.
4586 */
4587 dns_resolver_reset_ds_digests(view->resolver);
4588 disabled = NULL;
4589 (void)named_config_get(maps, "disable-ds-digests", &disabled);
4590 if (disabled != NULL) {
4591 for (element = cfg_list_first(disabled);
4592 element != NULL;
4593 element = cfg_list_next(element))
4594 CHECK(disable_ds_digests(cfg_listelt_value(element),
4595 view->resolver));
4596 }
4597
4598 /*
4599 * A global or view "forwarders" option, if present,
4600 * creates an entry for "." in the forwarding table.
4601 */
4602 forwardtype = NULL;
4603 forwarders = NULL;
4604 (void)named_config_get(maps, "forward", &forwardtype);
4605 (void)named_config_get(maps, "forwarders", &forwarders);
4606 if (forwarders != NULL)
4607 CHECK(configure_forward(config, view, dns_rootname,
4608 forwarders, forwardtype));
4609
4610 /*
4611 * Dual Stack Servers.
4612 */
4613 alternates = NULL;
4614 (void)named_config_get(maps, "dual-stack-servers", &alternates);
4615 if (alternates != NULL)
4616 CHECK(configure_alternates(config, view, alternates));
4617
4618 /*
4619 * We have default hints for class IN if we need them.
4620 */
4621 if (view->rdclass == dns_rdataclass_in && view->hints == NULL)
4622 dns_view_sethints(view, named_g_server->in_roothints);
4623
4624 /*
4625 * If we still have no hints, this is a non-IN view with no
4626 * "hints zone" configured. Issue a warning, except if this
4627 * is a root server. Root servers never need to consult
4628 * their hints, so it's no point requiring users to configure
4629 * them.
4630 */
4631 if (view->hints == NULL) {
4632 dns_zone_t *rootzone = NULL;
4633 (void)dns_view_findzone(view, dns_rootname, &rootzone);
4634 if (rootzone != NULL) {
4635 dns_zone_detach(&rootzone);
4636 need_hints = false;
4637 }
4638 if (need_hints)
4639 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
4640 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
4641 "no root hints for view '%s'",
4642 view->name);
4643 }
4644
4645 /*
4646 * Configure the view's TSIG keys.
4647 */
4648 CHECK(named_tsigkeyring_fromconfig(config, vconfig,
4649 view->mctx, &ring));
4650 if (named_g_server->sessionkey != NULL) {
4651 CHECK(dns_tsigkeyring_add(ring,
4652 named_g_server->session_keyname,
4653 named_g_server->sessionkey));
4654 }
4655 dns_view_setkeyring(view, ring);
4656 dns_tsigkeyring_detach(&ring);
4657
4658 /*
4659 * See if we can re-use a dynamic key ring.
4660 */
4661 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
4662 view->rdclass, &pview);
4663 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
4664 goto cleanup;
4665 if (pview != NULL) {
4666 dns_view_getdynamickeyring(pview, &ring);
4667 if (ring != NULL)
4668 dns_view_setdynamickeyring(view, ring);
4669 dns_tsigkeyring_detach(&ring);
4670 dns_view_detach(&pview);
4671 } else
4672 dns_view_restorekeyring(view);
4673
4674 /*
4675 * Configure the view's peer list.
4676 */
4677 {
4678 const cfg_obj_t *peers = NULL;
4679 dns_peerlist_t *newpeers = NULL;
4680
4681 (void)named_config_get(cfgmaps, "server", &peers);
4682 CHECK(dns_peerlist_new(mctx, &newpeers));
4683 for (element = cfg_list_first(peers);
4684 element != NULL;
4685 element = cfg_list_next(element))
4686 {
4687 const cfg_obj_t *cpeer = cfg_listelt_value(element);
4688 dns_peer_t *peer;
4689
4690 CHECK(configure_peer(cpeer, mctx, &peer));
4691 dns_peerlist_addpeer(newpeers, peer);
4692 dns_peer_detach(&peer);
4693 }
4694 dns_peerlist_detach(&view->peers);
4695 view->peers = newpeers; /* Transfer ownership. */
4696 }
4697
4698 /*
4699 * Configure the views rrset-order.
4700 */
4701 {
4702 const cfg_obj_t *rrsetorder = NULL;
4703
4704 (void)named_config_get(maps, "rrset-order", &rrsetorder);
4705 CHECK(dns_order_create(mctx, &order));
4706 for (element = cfg_list_first(rrsetorder);
4707 element != NULL;
4708 element = cfg_list_next(element))
4709 {
4710 const cfg_obj_t *ent = cfg_listelt_value(element);
4711
4712 CHECK(configure_order(order, ent));
4713 }
4714 if (view->order != NULL)
4715 dns_order_detach(&view->order);
4716 dns_order_attach(order, &view->order);
4717 dns_order_detach(&order);
4718 }
4719 /*
4720 * Copy the aclenv object.
4721 */
4722 dns_aclenv_copy(&view->aclenv,
4723 ns_interfacemgr_getaclenv(named_g_server->interfacemgr));
4724
4725 /*
4726 * Configure the "match-clients" and "match-destinations" ACL.
4727 * (These are only meaningful at the view level, but 'config'
4728 * must be passed so that named ACLs defined at the global level
4729 * can be retrieved.)
4730 */
4731 CHECK(configure_view_acl(vconfig, config, NULL, "match-clients",
4732 NULL, actx, named_g_mctx,
4733 &view->matchclients));
4734 CHECK(configure_view_acl(vconfig, config, NULL, "match-destinations",
4735 NULL, actx, named_g_mctx,
4736 &view->matchdestinations));
4737
4738 /*
4739 * Configure the "match-recursive-only" option.
4740 */
4741 obj = NULL;
4742 (void)named_config_get(maps, "match-recursive-only", &obj);
4743 if (obj != NULL && cfg_obj_asboolean(obj))
4744 view->matchrecursiveonly = true;
4745 else
4746 view->matchrecursiveonly = false;
4747
4748 /*
4749 * Configure other configurable data.
4750 */
4751 obj = NULL;
4752 result = named_config_get(maps, "recursion", &obj);
4753 INSIST(result == ISC_R_SUCCESS);
4754 view->recursion = cfg_obj_asboolean(obj);
4755
4756 obj = NULL;
4757 result = named_config_get(maps, "qname-minimization", &obj);
4758 INSIST(result == ISC_R_SUCCESS);
4759 qminmode = cfg_obj_asstring(obj);
4760 INSIST(qminmode != NULL);
4761 if (!strcmp(qminmode, "strict")) {
4762 view->qminimization = true;
4763 view->qmin_strict = true;
4764 } else if (!strcmp(qminmode, "relaxed")) {
4765 view->qminimization = true;
4766 view->qmin_strict = false;
4767 } else { /* "disabled" or "off" */
4768 view->qminimization = false;
4769 view->qmin_strict = false;
4770 }
4771
4772 obj = NULL;
4773 result = named_config_get(maps, "auth-nxdomain", &obj);
4774 INSIST(result == ISC_R_SUCCESS);
4775 view->auth_nxdomain = cfg_obj_asboolean(obj);
4776
4777 obj = NULL;
4778 result = named_config_get(maps, "glue-cache", &obj);
4779 INSIST(result == ISC_R_SUCCESS);
4780 view->use_glue_cache = cfg_obj_asboolean(obj);
4781
4782 obj = NULL;
4783 result = named_config_get(maps, "minimal-any", &obj);
4784 INSIST(result == ISC_R_SUCCESS);
4785 view->minimal_any = cfg_obj_asboolean(obj);
4786
4787 obj = NULL;
4788 result = named_config_get(maps, "minimal-responses", &obj);
4789 INSIST(result == ISC_R_SUCCESS);
4790 if (cfg_obj_isboolean(obj)) {
4791 if (cfg_obj_asboolean(obj))
4792 view->minimalresponses = dns_minimal_yes;
4793 else
4794 view->minimalresponses = dns_minimal_no;
4795 } else {
4796 str = cfg_obj_asstring(obj);
4797 if (strcasecmp(str, "no-auth") == 0) {
4798 view->minimalresponses = dns_minimal_noauth;
4799 } else if (strcasecmp(str, "no-auth-recursive") == 0) {
4800 view->minimalresponses = dns_minimal_noauthrec;
4801 } else {
4802 INSIST(0);
4803 ISC_UNREACHABLE();
4804 }
4805 }
4806
4807 obj = NULL;
4808 result = named_config_get(maps, "transfer-format", &obj);
4809 INSIST(result == ISC_R_SUCCESS);
4810 str = cfg_obj_asstring(obj);
4811 if (strcasecmp(str, "many-answers") == 0) {
4812 view->transfer_format = dns_many_answers;
4813 } else if (strcasecmp(str, "one-answer") == 0) {
4814 view->transfer_format = dns_one_answer;
4815 } else {
4816 INSIST(0);
4817 ISC_UNREACHABLE();
4818 }
4819
4820 obj = NULL;
4821 result = named_config_get(maps, "trust-anchor-telemetry", &obj);
4822 INSIST(result == ISC_R_SUCCESS);
4823 view->trust_anchor_telemetry = cfg_obj_asboolean(obj);
4824
4825 obj = NULL;
4826 result = named_config_get(maps, "root-key-sentinel", &obj);
4827 INSIST(result == ISC_R_SUCCESS);
4828 view->root_key_sentinel = cfg_obj_asboolean(obj);
4829
4830 /*
4831 * Set the "allow-query", "allow-query-cache", "allow-recursion",
4832 * "allow-recursion-on" and "allow-query-cache-on" ACLs if
4833 * configured in named.conf, but NOT from the global defaults.
4834 * This is done by leaving the third argument to configure_view_acl()
4835 * NULL.
4836 *
4837 * We ignore the global defaults here because these ACLs
4838 * can inherit from each other. If any are still unset after
4839 * applying the inheritance rules, we'll look up the defaults at
4840 * that time.
4841 */
4842
4843 /* named.conf only */
4844 CHECK(configure_view_acl(vconfig, config, NULL,
4845 "allow-query", NULL, actx,
4846 named_g_mctx, &view->queryacl));
4847
4848 /* named.conf only */
4849 CHECK(configure_view_acl(vconfig, config, NULL,
4850 "allow-query-cache", NULL, actx,
4851 named_g_mctx, &view->cacheacl));
4852 /* named.conf only */
4853 CHECK(configure_view_acl(vconfig, config, NULL,
4854 "allow-query-cache-on", NULL, actx,
4855 named_g_mctx, &view->cacheonacl));
4856
4857 if (strcmp(view->name, "_bind") != 0 &&
4858 view->rdclass != dns_rdataclass_chaos)
4859 {
4860 /* named.conf only */
4861 CHECK(configure_view_acl(vconfig, config, NULL,
4862 "allow-recursion", NULL, actx,
4863 named_g_mctx, &view->recursionacl));
4864 /* named.conf only */
4865 CHECK(configure_view_acl(vconfig, config, NULL,
4866 "allow-recursion-on", NULL, actx,
4867 named_g_mctx, &view->recursiononacl));
4868 }
4869
4870 if (view->recursion) {
4871 /*
4872 * "allow-query-cache" inherits from "allow-recursion" if set,
4873 * otherwise from "allow-query" if set.
4874 */
4875 if (view->cacheacl == NULL) {
4876 if (view->recursionacl != NULL) {
4877 dns_acl_attach(view->recursionacl,
4878 &view->cacheacl);
4879 } else if (view->queryacl != NULL) {
4880 dns_acl_attach(view->queryacl,
4881 &view->cacheacl);
4882 }
4883 }
4884
4885 /*
4886 * "allow-recursion" inherits from "allow-query-cache" if set,
4887 * otherwise from "allow-query" if set.
4888 */
4889 if (view->recursionacl == NULL) {
4890 if (view->cacheacl != NULL) {
4891 dns_acl_attach(view->cacheacl,
4892 &view->recursionacl);
4893 } else if (view->queryacl != NULL) {
4894 dns_acl_attach(view->queryacl,
4895 &view->recursionacl);
4896 }
4897 }
4898
4899 /*
4900 * "allow-query-cache-on" inherits from "allow-recursion-on"
4901 * if set.
4902 */
4903 if (view->cacheonacl == NULL) {
4904 if (view->recursiononacl != NULL) {
4905 dns_acl_attach(view->recursiononacl,
4906 &view->cacheonacl);
4907 }
4908 }
4909
4910 /*
4911 * "allow-recursion-on" inherits from "allow-query-cache-on"
4912 * if set.
4913 */
4914 if (view->recursiononacl == NULL) {
4915 if (view->cacheonacl != NULL) {
4916 dns_acl_attach(view->cacheonacl,
4917 &view->recursiononacl);
4918 }
4919 }
4920
4921 /*
4922 * If any are still unset at this point, we now get default
4923 * values for from the global config.
4924 */
4925
4926 if (view->recursionacl == NULL) {
4927 /* global default only */
4928 CHECK(configure_view_acl(NULL, NULL, named_g_config,
4929 "allow-recursion", NULL,
4930 actx, named_g_mctx,
4931 &view->recursionacl));
4932 }
4933 if (view->recursiononacl == NULL) {
4934 /* global default only */
4935 CHECK(configure_view_acl(NULL, NULL, named_g_config,
4936 "allow-recursion-on", NULL,
4937 actx, named_g_mctx,
4938 &view->recursiononacl));
4939 }
4940 if (view->cacheacl == NULL) {
4941 /* global default only */
4942 CHECK(configure_view_acl(NULL, NULL, named_g_config,
4943 "allow-query-cache", NULL,
4944 actx, named_g_mctx,
4945 &view->cacheacl));
4946 }
4947 if (view->cacheonacl == NULL) {
4948 /* global default only */
4949 CHECK(configure_view_acl(NULL, NULL, named_g_config,
4950 "allow-query-cache-on", NULL,
4951 actx, named_g_mctx,
4952 &view->cacheonacl));
4953 }
4954 } else {
4955 /*
4956 * We're not recursive; if the query-cache ACLs haven't
4957 * been set at the options/view level, set them to none.
4958 */
4959 if (view->cacheacl == NULL) {
4960 CHECK(dns_acl_none(mctx, &view->cacheacl));
4961 }
4962 if (view->cacheonacl == NULL) {
4963 CHECK(dns_acl_none(mctx, &view->cacheonacl));
4964 }
4965 }
4966
4967 /*
4968 * Finished setting recursion and query-cache ACLs, so now we
4969 * can get the allow-query default if it wasn't set in named.conf
4970 */
4971 if (view->queryacl == NULL) {
4972 /* global default only */
4973 CHECK(configure_view_acl(NULL, NULL, named_g_config,
4974 "allow-query", NULL,
4975 actx, named_g_mctx,
4976 &view->queryacl));
4977 }
4978
4979 /*
4980 * Ignore case when compressing responses to the specified
4981 * clients. This causes case not always to be preserved,
4982 * and is needed by some broken clients.
4983 */
4984 CHECK(configure_view_acl(vconfig, config, named_g_config,
4985 "no-case-compress", NULL, actx,
4986 named_g_mctx, &view->nocasecompress));
4987
4988 /*
4989 * Disable name compression completely, this is a tradeoff
4990 * between CPU and network usage.
4991 */
4992 obj = NULL;
4993 result = named_config_get(maps, "message-compression", &obj);
4994 INSIST(result == ISC_R_SUCCESS);
4995 view->msgcompression = cfg_obj_asboolean(obj);
4996
4997 /*
4998 * Filter setting on addresses in the answer section.
4999 */
5000 CHECK(configure_view_acl(vconfig, config, named_g_config,
5001 "deny-answer-addresses", "acl",
5002 actx, named_g_mctx,
5003 &view->denyansweracl));
5004 CHECK(configure_view_nametable(vconfig, config, "deny-answer-addresses",
5005 "except-from", named_g_mctx,
5006 &view->answeracl_exclude));
5007
5008 /*
5009 * Filter setting on names (CNAME/DNAME targets) in the answer section.
5010 */
5011 CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5012 "name", named_g_mctx,
5013 &view->denyanswernames));
5014 CHECK(configure_view_nametable(vconfig, config, "deny-answer-aliases",
5015 "except-from", named_g_mctx,
5016 &view->answernames_exclude));
5017
5018 /*
5019 * Configure sortlist, if set
5020 */
5021 CHECK(configure_view_sortlist(vconfig, config, actx, named_g_mctx,
5022 &view->sortlist));
5023
5024 /*
5025 * Configure default allow-update and allow-update-forwarding ACLs,
5026 * so they can be inherited by zones. (XXX: These are not
5027 * read from the options/view level here. However, they may be
5028 * read from there in zoneconf.c:configure_zone_acl() later.)
5029 */
5030 if (view->updateacl == NULL) {
5031 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5032 "allow-update", NULL, actx,
5033 named_g_mctx, &view->updateacl));
5034 }
5035 if (view->upfwdacl == NULL) {
5036 CHECK(configure_view_acl(NULL, NULL, named_g_config,
5037 "allow-update-forwarding", NULL, actx,
5038 named_g_mctx, &view->upfwdacl));
5039 }
5040
5041 /*
5042 * Configure default allow-transfer and allow-notify ACLs so they
5043 * can be inherited by zones.
5044 */
5045 if (view->transferacl == NULL) {
5046 CHECK(configure_view_acl(vconfig, config, named_g_config,
5047 "allow-transfer", NULL, actx,
5048 named_g_mctx, &view->transferacl));
5049 }
5050 if (view->notifyacl == NULL) {
5051 CHECK(configure_view_acl(vconfig, config, named_g_config,
5052 "allow-notify", NULL, actx,
5053 named_g_mctx, &view->notifyacl));
5054 }
5055
5056 obj = NULL;
5057 result = named_config_get(maps, "provide-ixfr", &obj);
5058 INSIST(result == ISC_R_SUCCESS);
5059 view->provideixfr = cfg_obj_asboolean(obj);
5060
5061 obj = NULL;
5062 result = named_config_get(maps, "request-nsid", &obj);
5063 INSIST(result == ISC_R_SUCCESS);
5064 view->requestnsid = cfg_obj_asboolean(obj);
5065
5066 obj = NULL;
5067 result = named_config_get(maps, "send-cookie", &obj);
5068 INSIST(result == ISC_R_SUCCESS);
5069 view->sendcookie = cfg_obj_asboolean(obj);
5070
5071 obj = NULL;
5072 if (view->pad_acl != NULL)
5073 dns_acl_detach(&view->pad_acl);
5074 result = named_config_get(optionmaps, "response-padding", &obj);
5075 if (result == ISC_R_SUCCESS) {
5076 const cfg_obj_t *padobj = cfg_tuple_get(obj, "block-size");
5077 const cfg_obj_t *aclobj = cfg_tuple_get(obj, "acl");
5078 uint32_t padding = cfg_obj_asuint32(padobj);
5079
5080 if (padding > 512U) {
5081 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
5082 "response-padding block-size cannot "
5083 "exceed 512: lowering");
5084 padding = 512U;
5085 }
5086 view->padding = (uint16_t)padding;
5087 CHECK(cfg_acl_fromconfig(aclobj, config, named_g_lctx,
5088 actx, named_g_mctx, 0,
5089 &view->pad_acl));
5090 }
5091
5092 obj = NULL;
5093 result = named_config_get(maps, "require-server-cookie", &obj);
5094 INSIST(result == ISC_R_SUCCESS);
5095 view->requireservercookie = cfg_obj_asboolean(obj);
5096
5097 obj = NULL;
5098 result = named_config_get(maps, "v6-bias", &obj);
5099 INSIST(result == ISC_R_SUCCESS);
5100 view->v6bias = cfg_obj_asuint32(obj) * 1000;
5101
5102 obj = NULL;
5103 result = named_config_get(maps, "max-clients-per-query", &obj);
5104 INSIST(result == ISC_R_SUCCESS);
5105 max_clients_per_query = cfg_obj_asuint32(obj);
5106
5107 obj = NULL;
5108 result = named_config_get(maps, "clients-per-query", &obj);
5109 INSIST(result == ISC_R_SUCCESS);
5110 dns_resolver_setclientsperquery(view->resolver,
5111 cfg_obj_asuint32(obj),
5112 max_clients_per_query);
5113
5114 obj = NULL;
5115 result = named_config_get(maps, "max-recursion-depth", &obj);
5116 INSIST(result == ISC_R_SUCCESS);
5117 dns_resolver_setmaxdepth(view->resolver, cfg_obj_asuint32(obj));
5118
5119 obj = NULL;
5120 result = named_config_get(maps, "max-recursion-queries", &obj);
5121 INSIST(result == ISC_R_SUCCESS);
5122 dns_resolver_setmaxqueries(view->resolver, cfg_obj_asuint32(obj));
5123
5124 obj = NULL;
5125 result = named_config_get(maps, "fetches-per-zone", &obj);
5126 INSIST(result == ISC_R_SUCCESS);
5127 obj2 = cfg_tuple_get(obj, "fetches");
5128 dns_resolver_setfetchesperzone(view->resolver, cfg_obj_asuint32(obj2));
5129 obj2 = cfg_tuple_get(obj, "response");
5130 if (!cfg_obj_isvoid(obj2)) {
5131 const char *resp = cfg_obj_asstring(obj2);
5132 isc_result_t r = DNS_R_SERVFAIL;
5133
5134 if (strcasecmp(resp, "drop") == 0) {
5135 r = DNS_R_DROP;
5136 } else if (strcasecmp(resp, "fail") == 0) {
5137 r = DNS_R_SERVFAIL;
5138 } else {
5139 INSIST(0);
5140 ISC_UNREACHABLE();
5141 }
5142
5143 dns_resolver_setquotaresponse(view->resolver,
5144 dns_quotatype_zone, r);
5145 }
5146
5147 obj = NULL;
5148 result = named_config_get(maps, "prefetch", &obj);
5149 if (result == ISC_R_SUCCESS) {
5150 const cfg_obj_t *trigger, *eligible;
5151
5152 trigger = cfg_tuple_get(obj, "trigger");
5153 view->prefetch_trigger = cfg_obj_asuint32(trigger);
5154 if (view->prefetch_trigger > 10)
5155 view->prefetch_trigger = 10;
5156 eligible = cfg_tuple_get(obj, "eligible");
5157 if (cfg_obj_isvoid(eligible)) {
5158 int m;
5159 for (m = 1; maps[m] != NULL; m++) {
5160 obj = NULL;
5161 result = named_config_get(&maps[m],
5162 "prefetch", &obj);
5163 INSIST(result == ISC_R_SUCCESS);
5164 eligible = cfg_tuple_get(obj, "eligible");
5165 if (cfg_obj_isuint32(eligible))
5166 break;
5167 }
5168 INSIST(cfg_obj_isuint32(eligible));
5169 }
5170 view->prefetch_eligible = cfg_obj_asuint32(eligible);
5171 if (view->prefetch_eligible < view->prefetch_trigger + 6)
5172 view->prefetch_eligible = view->prefetch_trigger + 6;
5173 }
5174
5175 obj = NULL;
5176 result = named_config_get(optionmaps, "dnssec-lookaside", &obj);
5177 if (result == ISC_R_SUCCESS) {
5178 /* "auto" is deprecated, log a warning if seen */
5179 const char *dom;
5180 dlvobj = cfg_listelt_value(cfg_list_first(obj));
5181 dom = cfg_obj_asstring(cfg_tuple_get(dlvobj, "domain"));
5182 if (cfg_obj_isvoid(cfg_tuple_get(dlvobj, "trust-anchor"))) {
5183 /* If "no", skip; if "auto", log warning */
5184 if (!strcasecmp(dom, "no")) {
5185 result = ISC_R_NOTFOUND;
5186 } else if (!strcasecmp(dom, "auto")) {
5187 /*
5188 * Warning logged by libbind9.
5189 */
5190 result = ISC_R_NOTFOUND;
5191 }
5192 }
5193 }
5194
5195 if (result == ISC_R_SUCCESS) {
5196 dns_name_t *dlv, *iscdlv;
5197 dns_fixedname_t f;
5198
5199 /* Also log a warning if manually configured to dlv.isc.org */
5200 iscdlv = dns_fixedname_initname(&f);
5201 CHECK(dns_name_fromstring(iscdlv, "dlv.isc.org", 0, NULL));
5202
5203 for (element = cfg_list_first(obj);
5204 element != NULL;
5205 element = cfg_list_next(element))
5206 {
5207 obj = cfg_listelt_value(element);
5208 obj = cfg_tuple_get(obj, "trust-anchor");
5209
5210 dlv = dns_fixedname_name(&view->dlv_fixed);
5211 CHECK(dns_name_fromstring(dlv, cfg_obj_asstring(obj),
5212 DNS_NAME_DOWNCASE, NULL));
5213 if (dns_name_equal(dlv, iscdlv)) {
5214 /*
5215 * Warning logged by libbind9.
5216 */
5217 view->dlv = NULL;
5218 } else {
5219 view->dlv = dlv;
5220 }
5221 }
5222 } else {
5223 view->dlv = NULL;
5224 }
5225
5226 /*
5227 * For now, there is only one kind of trusted keys, the
5228 * "security roots".
5229 */
5230 CHECK(configure_view_dnsseckeys(view, vconfig, config, bindkeys,
5231 auto_root, mctx));
5232 dns_resolver_resetmustbesecure(view->resolver);
5233 obj = NULL;
5234 result = named_config_get(maps, "dnssec-must-be-secure", &obj);
5235 if (result == ISC_R_SUCCESS)
5236 CHECK(mustbesecure(obj, view->resolver));
5237
5238 obj = NULL;
5239 result = named_config_get(maps, "nta-recheck", &obj);
5240 INSIST(result == ISC_R_SUCCESS);
5241 view->nta_recheck = cfg_obj_asuint32(obj);
5242
5243 obj = NULL;
5244 result = named_config_get(maps, "nta-lifetime", &obj);
5245 INSIST(result == ISC_R_SUCCESS);
5246 view->nta_lifetime = cfg_obj_asuint32(obj);
5247
5248 obj = NULL;
5249 result = named_config_get(maps, "preferred-glue", &obj);
5250 if (result == ISC_R_SUCCESS) {
5251 str = cfg_obj_asstring(obj);
5252 if (strcasecmp(str, "a") == 0)
5253 view->preferred_glue = dns_rdatatype_a;
5254 else if (strcasecmp(str, "aaaa") == 0)
5255 view->preferred_glue = dns_rdatatype_aaaa;
5256 else
5257 view->preferred_glue = 0;
5258 } else
5259 view->preferred_glue = 0;
5260
5261 obj = NULL;
5262 result = named_config_get(maps, "root-delegation-only", &obj);
5263 if (result == ISC_R_SUCCESS)
5264 dns_view_setrootdelonly(view, true);
5265 if (result == ISC_R_SUCCESS && ! cfg_obj_isvoid(obj)) {
5266 const cfg_obj_t *exclude;
5267 dns_fixedname_t fixed;
5268 dns_name_t *name;
5269
5270 name = dns_fixedname_initname(&fixed);
5271 for (element = cfg_list_first(obj);
5272 element != NULL;
5273 element = cfg_list_next(element))
5274 {
5275 exclude = cfg_listelt_value(element);
5276 CHECK(dns_name_fromstring(name,
5277 cfg_obj_asstring(exclude),
5278 0, NULL));
5279 CHECK(dns_view_excludedelegationonly(view, name));
5280 }
5281 } else
5282 dns_view_setrootdelonly(view, false);
5283
5284 /*
5285 * Load DynDB modules.
5286 */
5287 dyndb_list = NULL;
5288 if (voptions != NULL) {
5289 (void)cfg_map_get(voptions, "dyndb", &dyndb_list);
5290 } else {
5291 (void)cfg_map_get(config, "dyndb", &dyndb_list);
5292 }
5293
5294#ifdef HAVE_DLOPEN
5295 for (element = cfg_list_first(dyndb_list);
5296 element != NULL;
5297 element = cfg_list_next(element))
5298 {
5299 const cfg_obj_t *dyndb = cfg_listelt_value(element);
5300
5301 if (dctx == NULL) {
5302 const void *hashinit = isc_hash_get_initializer();
5303 CHECK(dns_dyndb_createctx(mctx, hashinit,
5304 named_g_lctx, view,
5305 named_g_server->zonemgr,
5306 named_g_server->task,
5307 named_g_timermgr, &dctx));
5308 }
5309
5310 CHECK(configure_dyndb(dyndb, mctx, dctx));
5311 }
5312#endif
5313
5314 /*
5315 * Load plugins.
5316 */
5317 plugin_list = NULL;
5318 if (voptions != NULL) {
5319 (void)cfg_map_get(voptions, "plugin", &plugin_list);
5320 } else {
5321 (void)cfg_map_get(config, "plugin", &plugin_list);
5322 }
5323
5324#ifdef HAVE_DLOPEN
5325 if (plugin_list != NULL) {
5326 INSIST(view->hooktable == NULL);
5327 CHECK(ns_hooktable_create(view->mctx,
5328 (ns_hooktable_t **) &view->hooktable));
5329 view->hooktable_free = ns_hooktable_free;
5330
5331 ns_plugins_create(view->mctx, (ns_plugins_t **)&view->plugins);
5332 view->plugins_free = ns_plugins_free;
5333
5334 CHECK(cfg_pluginlist_foreach(config, plugin_list, named_g_lctx,
5335 register_one_plugin, view));
5336 }
5337#endif
5338
5339 /*
5340 * Setup automatic empty zones. If recursion is off then
5341 * they are disabled by default.
5342 */
5343 obj = NULL;
5344 (void)named_config_get(maps, "empty-zones-enable", &obj);
5345 (void)named_config_get(maps, "disable-empty-zone", &disablelist);
5346 if (obj == NULL && disablelist == NULL &&
5347 view->rdclass == dns_rdataclass_in) {
5348 empty_zones_enable = view->recursion;
5349 } else if (view->rdclass == dns_rdataclass_in) {
5350 if (obj != NULL)
5351 empty_zones_enable = cfg_obj_asboolean(obj);
5352 else
5353 empty_zones_enable = view->recursion;
5354 } else {
5355 empty_zones_enable = false;
5356 }
5357
5358 if (empty_zones_enable) {
5359 const char *empty;
5360 int empty_zone = 0;
5361 dns_fixedname_t fixed;
5362 dns_name_t *name;
5363 isc_buffer_t buffer;
5364 char server[DNS_NAME_FORMATSIZE + 1];
5365 char contact[DNS_NAME_FORMATSIZE + 1];
5366 const char *empty_dbtype[4] =
5367 { "_builtin", "empty", NULL, NULL };
5368 int empty_dbtypec = 4;
5369 dns_zonestat_level_t statlevel = dns_zonestat_none;
5370
5371 name = dns_fixedname_initname(&fixed);
5372
5373 obj = NULL;
5374 result = named_config_get(maps, "empty-server", &obj);
5375 if (result == ISC_R_SUCCESS) {
5376 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5377 0, NULL));
5378 isc_buffer_init(&buffer, server, sizeof(server) - 1);
5379 CHECK(dns_name_totext(name, false, &buffer));
5380 server[isc_buffer_usedlength(&buffer)] = 0;
5381 empty_dbtype[2] = server;
5382 } else
5383 empty_dbtype[2] = "@";
5384
5385 obj = NULL;
5386 result = named_config_get(maps, "empty-contact", &obj);
5387 if (result == ISC_R_SUCCESS) {
5388 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj),
5389 0, NULL));
5390 isc_buffer_init(&buffer, contact, sizeof(contact) - 1);
5391 CHECK(dns_name_totext(name, false, &buffer));
5392 contact[isc_buffer_usedlength(&buffer)] = 0;
5393 empty_dbtype[3] = contact;
5394 } else
5395 empty_dbtype[3] = ".";
5396
5397 obj = NULL;
5398 result = named_config_get(maps, "zone-statistics", &obj);
5399 INSIST(result == ISC_R_SUCCESS);
5400 if (cfg_obj_isboolean(obj)) {
5401 if (cfg_obj_asboolean(obj))
5402 statlevel = dns_zonestat_full;
5403 else
5404 statlevel = dns_zonestat_none;
5405 } else {
5406 const char *levelstr = cfg_obj_asstring(obj);
5407 if (strcasecmp(levelstr, "full") == 0) {
5408 statlevel = dns_zonestat_full;
5409 } else if (strcasecmp(levelstr, "terse") == 0) {
5410 statlevel = dns_zonestat_terse;
5411 } else if (strcasecmp(levelstr, "none") == 0) {
5412 statlevel = dns_zonestat_none;
5413 } else {
5414 INSIST(0);
5415 ISC_UNREACHABLE();
5416 }
5417 }
5418
5419 for (empty = empty_zones[empty_zone];
5420 empty != NULL;
5421 empty = empty_zones[++empty_zone])
5422 {
5423 dns_forwarders_t *dnsforwarders = NULL;
5424
5425 /*
5426 * Look for zone on drop list.
5427 */
5428 CHECK(dns_name_fromstring(name, empty, 0, NULL));
5429 if (disablelist != NULL &&
5430 on_disable_list(disablelist, name))
5431 continue;
5432
5433 /*
5434 * This zone already exists.
5435 */
5436 (void)dns_view_findzone(view, name, &zone);
5437 if (zone != NULL) {
5438 dns_zone_detach(&zone);
5439 continue;
5440 }
5441
5442 /*
5443 * If we would forward this name don't add a
5444 * empty zone for it.
5445 */
5446 result = dns_fwdtable_find(view->fwdtable, name,
5447 NULL, &dnsforwarders);
5448 if (result == ISC_R_SUCCESS &&
5449 dnsforwarders->fwdpolicy == dns_fwdpolicy_only)
5450 continue;
5451
5452 /*
5453 * See if we can re-use a existing zone.
5454 */
5455 result = dns_viewlist_find(&named_g_server->viewlist,
5456 view->name, view->rdclass,
5457 &pview);
5458 if (result != ISC_R_NOTFOUND &&
5459 result != ISC_R_SUCCESS)
5460 goto cleanup;
5461
5462 if (pview != NULL) {
5463 (void)dns_view_findzone(pview, name, &zone);
5464 dns_view_detach(&pview);
5465 }
5466
5467 CHECK(create_empty_zone(zone, name, view, zonelist,
5468 empty_dbtype, empty_dbtypec,
5469 statlevel));
5470 if (zone != NULL)
5471 dns_zone_detach(&zone);
5472 }
5473 }
5474
5475 obj = NULL;
5476 result = named_config_get(maps, "rate-limit", &obj);
5477 if (result == ISC_R_SUCCESS) {
5478 result = configure_rrl(view, config, obj);
5479 if (result != ISC_R_SUCCESS)
5480 goto cleanup;
5481 }
5482
5483 /*
5484 * Set the servfail-ttl.
5485 */
5486 obj = NULL;
5487 result = named_config_get(maps, "servfail-ttl", &obj);
5488 INSIST(result == ISC_R_SUCCESS);
5489 fail_ttl = cfg_obj_asuint32(obj);
5490 if (fail_ttl > 30)
5491 fail_ttl = 30;
5492 dns_view_setfailttl(view, fail_ttl);
5493
5494 /*
5495 * Name space to look up redirect information in.
5496 */
5497 obj = NULL;
5498 result = named_config_get(maps, "nxdomain-redirect", &obj);
5499 if (result == ISC_R_SUCCESS) {
5500 dns_name_t *name = dns_fixedname_name(&view->redirectfixed);
5501 CHECK(dns_name_fromstring(name, cfg_obj_asstring(obj), 0,
5502 NULL));
5503 view->redirectzone = name;
5504 } else {
5505 view->redirectzone = NULL;
5506 }
5507
5508 /*
5509 * Exceptions to DNSSEC validation.
5510 */
5511 obj = NULL;
5512 result = named_config_get(maps, "validate-except", &obj);
5513 if (result == ISC_R_SUCCESS) {
5514 result = dns_view_getntatable(view, &ntatable);
5515 }
5516 if (result == ISC_R_SUCCESS) {
5517 for (element = cfg_list_first(obj);
5518 element != NULL;
5519 element = cfg_list_next(element))
5520 {
5521 dns_fixedname_t fntaname;
5522 dns_name_t *ntaname;
5523
5524 ntaname = dns_fixedname_initname(&fntaname);
5525 obj = cfg_listelt_value(element);
5526 CHECK(dns_name_fromstring(ntaname,
5527 cfg_obj_asstring(obj),
5528 0, NULL));
5529 CHECK(dns_ntatable_add(ntatable, ntaname,
5530 true, 0, 0xffffffffU));
5531 }
5532 }
5533
5534#ifdef HAVE_DNSTAP
5535 /*
5536 * Set up the dnstap environment and configure message
5537 * types to log.
5538 */
5539 CHECK(configure_dnstap(maps, view));
5540#endif /* HAVE_DNSTAP */
5541
5542 result = ISC_R_SUCCESS;
5543
5544 cleanup:
5545 if (ntatable != NULL) {
5546 dns_ntatable_detach(&ntatable);
5547 }
5548 if (clients != NULL) {
5549 dns_acl_detach(&clients);
5550 }
5551 if (mapped != NULL) {
5552 dns_acl_detach(&mapped);
5553 }
5554 if (excluded != NULL) {
5555 dns_acl_detach(&excluded);
5556 }
5557 if (ring != NULL) {
5558 dns_tsigkeyring_detach(&ring);
5559 }
5560 if (zone != NULL) {
5561 dns_zone_detach(&zone);
5562 }
5563 if (dispatch4 != NULL) {
5564 dns_dispatch_detach(&dispatch4);
5565 }
5566 if (dispatch6 != NULL) {
5567 dns_dispatch_detach(&dispatch6);
5568 }
5569 if (resstats != NULL) {
5570 isc_stats_detach(&resstats);
5571 }
5572 if (resquerystats != NULL) {
5573 dns_stats_detach(&resquerystats);
5574 }
5575 if (order != NULL) {
5576 dns_order_detach(&order);
5577 }
5578 if (cmctx != NULL) {
5579 isc_mem_detach(&cmctx);
5580 }
5581 if (hmctx != NULL) {
5582 isc_mem_detach(&hmctx);
5583 }
5584 if (cache != NULL) {
5585 dns_cache_detach(&cache);
5586 }
5587 if (dctx != NULL) {
5588 dns_dyndb_destroyctx(&dctx);
5589 }
5590
5591 return (result);
5592}
5593
5594static isc_result_t
5595configure_hints(dns_view_t *view, const char *filename) {
5596 isc_result_t result;
5597 dns_db_t *db;
5598
5599 db = NULL;
5600 result = dns_rootns_create(view->mctx, view->rdclass, filename, &db);
5601 if (result == ISC_R_SUCCESS) {
5602 dns_view_sethints(view, db);
5603 dns_db_detach(&db);
5604 }
5605
5606 return (result);
5607}
5608
5609static isc_result_t
5610configure_alternates(const cfg_obj_t *config, dns_view_t *view,
5611 const cfg_obj_t *alternates)
5612{
5613 const cfg_obj_t *portobj;
5614 const cfg_obj_t *addresses;
5615 const cfg_listelt_t *element;
5616 isc_result_t result = ISC_R_SUCCESS;
5617 in_port_t port;
5618
5619 /*
5620 * Determine which port to send requests to.
5621 */
5622 CHECKM(named_config_getport(config, &port), "port");
5623
5624 if (alternates != NULL) {
5625 portobj = cfg_tuple_get(alternates, "port");
5626 if (cfg_obj_isuint32(portobj)) {
5627 uint32_t val = cfg_obj_asuint32(portobj);
5628 if (val > UINT16_MAX) {
5629 cfg_obj_log(portobj, named_g_lctx,
5630 ISC_LOG_ERROR,
5631 "port '%u' out of range", val);
5632 return (ISC_R_RANGE);
5633 }
5634 port = (in_port_t) val;
5635 }
5636 }
5637
5638 addresses = NULL;
5639 if (alternates != NULL)
5640 addresses = cfg_tuple_get(alternates, "addresses");
5641
5642 for (element = cfg_list_first(addresses);
5643 element != NULL;
5644 element = cfg_list_next(element))
5645 {
5646 const cfg_obj_t *alternate = cfg_listelt_value(element);
5647 isc_sockaddr_t sa;
5648
5649 if (!cfg_obj_issockaddr(alternate)) {
5650 dns_fixedname_t fixed;
5651 dns_name_t *name;
5652 const char *str = cfg_obj_asstring(cfg_tuple_get(
5653 alternate, "name"));
5654 isc_buffer_t buffer;
5655 in_port_t myport = port;
5656
5657 isc_buffer_constinit(&buffer, str, strlen(str));
5658 isc_buffer_add(&buffer, strlen(str));
5659 name = dns_fixedname_initname(&fixed);
5660 CHECK(dns_name_fromtext(name, &buffer, dns_rootname, 0,
5661 NULL));
5662
5663 portobj = cfg_tuple_get(alternate, "port");
5664 if (cfg_obj_isuint32(portobj)) {
5665 uint32_t val = cfg_obj_asuint32(portobj);
5666 if (val > UINT16_MAX) {
5667 cfg_obj_log(portobj, named_g_lctx,
5668 ISC_LOG_ERROR,
5669 "port '%u' out of range",
5670 val);
5671 return (ISC_R_RANGE);
5672 }
5673 myport = (in_port_t) val;
5674 }
5675 CHECK(dns_resolver_addalternate(view->resolver, NULL,
5676 name, myport));
5677 continue;
5678 }
5679
5680 sa = *cfg_obj_assockaddr(alternate);
5681 if (isc_sockaddr_getport(&sa) == 0)
5682 isc_sockaddr_setport(&sa, port);
5683 CHECK(dns_resolver_addalternate(view->resolver, &sa,
5684 NULL, 0));
5685 }
5686
5687 cleanup:
5688 return (result);
5689}
5690
5691static isc_result_t
5692configure_forward(const cfg_obj_t *config, dns_view_t *view,
5693 const dns_name_t *origin, const cfg_obj_t *forwarders,
5694 const cfg_obj_t *forwardtype)
5695{
5696 const cfg_obj_t *portobj, *dscpobj;
5697 const cfg_obj_t *faddresses;
5698 const cfg_listelt_t *element;
5699 dns_fwdpolicy_t fwdpolicy = dns_fwdpolicy_none;
5700 dns_forwarderlist_t fwdlist;
5701 dns_forwarder_t *fwd;
5702 isc_result_t result;
5703 in_port_t port;
5704 isc_dscp_t dscp = -1;
5705
5706 ISC_LIST_INIT(fwdlist);
5707
5708 /*
5709 * Determine which port to send forwarded requests to.
5710 */
5711 CHECKM(named_config_getport(config, &port), "port");
5712
5713 if (forwarders != NULL) {
5714 portobj = cfg_tuple_get(forwarders, "port");
5715 if (cfg_obj_isuint32(portobj)) {
5716 uint32_t val = cfg_obj_asuint32(portobj);
5717 if (val > UINT16_MAX) {
5718 cfg_obj_log(portobj, named_g_lctx,
5719 ISC_LOG_ERROR,
5720 "port '%u' out of range", val);
5721 return (ISC_R_RANGE);
5722 }
5723 port = (in_port_t) val;
5724 }
5725 }
5726
5727 /*
5728 * DSCP value for forwarded requests.
5729 */
5730 dscp = named_g_dscp;
5731 if (forwarders != NULL) {
5732 dscpobj = cfg_tuple_get(forwarders, "dscp");
5733 if (cfg_obj_isuint32(dscpobj)) {
5734 if (cfg_obj_asuint32(dscpobj) > 63) {
5735 cfg_obj_log(dscpobj, named_g_lctx,
5736 ISC_LOG_ERROR,
5737 "dscp value '%u' is out of range",
5738 cfg_obj_asuint32(dscpobj));
5739 return (ISC_R_RANGE);
5740 }
5741 dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
5742 }
5743 }
5744
5745 faddresses = NULL;
5746 if (forwarders != NULL)
5747 faddresses = cfg_tuple_get(forwarders, "addresses");
5748
5749 for (element = cfg_list_first(faddresses);
5750 element != NULL;
5751 element = cfg_list_next(element))
5752 {
5753 const cfg_obj_t *forwarder = cfg_listelt_value(element);
5754 fwd = isc_mem_get(view->mctx, sizeof(dns_forwarder_t));
5755 if (fwd == NULL) {
5756 result = ISC_R_NOMEMORY;
5757 goto cleanup;
5758 }
5759 fwd->addr = *cfg_obj_assockaddr(forwarder);
5760 if (isc_sockaddr_getport(&fwd->addr) == 0)
5761 isc_sockaddr_setport(&fwd->addr, port);
5762 fwd->dscp = cfg_obj_getdscp(forwarder);
5763 if (fwd->dscp == -1)
5764 fwd->dscp = dscp;
5765 ISC_LINK_INIT(fwd, link);
5766 ISC_LIST_APPEND(fwdlist, fwd, link);
5767 }
5768
5769 if (ISC_LIST_EMPTY(fwdlist)) {
5770 if (forwardtype != NULL)
5771 cfg_obj_log(forwardtype, named_g_lctx, ISC_LOG_WARNING,
5772 "no forwarders seen; disabling "
5773 "forwarding");
5774 fwdpolicy = dns_fwdpolicy_none;
5775 } else {
5776 if (forwardtype == NULL) {
5777 fwdpolicy = dns_fwdpolicy_first;
5778 } else {
5779 const char *forwardstr = cfg_obj_asstring(forwardtype);
5780 if (strcasecmp(forwardstr, "first") == 0) {
5781 fwdpolicy = dns_fwdpolicy_first;
5782 } else if (strcasecmp(forwardstr, "only") == 0) {
5783 fwdpolicy = dns_fwdpolicy_only;
5784 } else {
5785 INSIST(0);
5786 ISC_UNREACHABLE();
5787 }
5788 }
5789 }
5790
5791 result = dns_fwdtable_addfwd(view->fwdtable, origin, &fwdlist,
5792 fwdpolicy);
5793 if (result != ISC_R_SUCCESS) {
5794 char namebuf[DNS_NAME_FORMATSIZE];
5795 dns_name_format(origin, namebuf, sizeof(namebuf));
5796 cfg_obj_log(forwarders, named_g_lctx, ISC_LOG_WARNING,
5797 "could not set up forwarding for domain '%s': %s",
5798 namebuf, isc_result_totext(result));
5799 goto cleanup;
5800 }
5801
5802 result = ISC_R_SUCCESS;
5803
5804 cleanup:
5805
5806 while (!ISC_LIST_EMPTY(fwdlist)) {
5807 fwd = ISC_LIST_HEAD(fwdlist);
5808 ISC_LIST_UNLINK(fwdlist, fwd, link);
5809 isc_mem_put(view->mctx, fwd, sizeof(dns_forwarder_t));
5810 }
5811
5812 return (result);
5813}
5814
5815static isc_result_t
5816get_viewinfo(const cfg_obj_t *vconfig, const char **namep,
5817 dns_rdataclass_t *classp)
5818{
5819 isc_result_t result = ISC_R_SUCCESS;
5820 const char *viewname;
5821 dns_rdataclass_t viewclass;
5822
5823 REQUIRE(namep != NULL && *namep == NULL);
5824 REQUIRE(classp != NULL);
5825
5826 if (vconfig != NULL) {
5827 const cfg_obj_t *classobj = NULL;
5828
5829 viewname = cfg_obj_asstring(cfg_tuple_get(vconfig, "name"));
5830 classobj = cfg_tuple_get(vconfig, "class");
5831 CHECK(named_config_getclass(classobj, dns_rdataclass_in,
5832 &viewclass));
5833 if (dns_rdataclass_ismeta(viewclass)) {
5834 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5835 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
5836 "view '%s': class must not be meta",
5837 viewname);
5838 CHECK(ISC_R_FAILURE);
5839 }
5840 } else {
5841 viewname = "_default";
5842 viewclass = dns_rdataclass_in;
5843 }
5844
5845 *namep = viewname;
5846 *classp = viewclass;
5847
5848cleanup:
5849 return (result);
5850}
5851
5852/*
5853 * Find a view based on its configuration info and attach to it.
5854 *
5855 * If 'vconfig' is NULL, attach to the default view.
5856 */
5857static isc_result_t
5858find_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
5859 dns_view_t **viewp)
5860{
5861 isc_result_t result;
5862 const char *viewname = NULL;
5863 dns_rdataclass_t viewclass;
5864 dns_view_t *view = NULL;
5865
5866 result = get_viewinfo(vconfig, &viewname, &viewclass);
5867 if (result != ISC_R_SUCCESS)
5868 return (result);
5869
5870 result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
5871 if (result != ISC_R_SUCCESS)
5872 return (result);
5873
5874 *viewp = view;
5875 return (ISC_R_SUCCESS);
5876}
5877
5878/*
5879 * Create a new view and add it to the list.
5880 *
5881 * If 'vconfig' is NULL, create the default view.
5882 *
5883 * The view created is attached to '*viewp'.
5884 */
5885static isc_result_t
5886create_view(const cfg_obj_t *vconfig, dns_viewlist_t *viewlist,
5887 dns_view_t **viewp)
5888{
5889 isc_result_t result;
5890 const char *viewname = NULL;
5891 dns_rdataclass_t viewclass;
5892 dns_view_t *view = NULL;
5893
5894 result = get_viewinfo(vconfig, &viewname, &viewclass);
5895 if (result != ISC_R_SUCCESS)
5896 return (result);
5897
5898 result = dns_viewlist_find(viewlist, viewname, viewclass, &view);
5899 if (result == ISC_R_SUCCESS)
5900 return (ISC_R_EXISTS);
5901 if (result != ISC_R_NOTFOUND)
5902 return (result);
5903 INSIST(view == NULL);
5904
5905 result = dns_view_create(named_g_mctx, viewclass, viewname, &view);
5906 if (result != ISC_R_SUCCESS)
5907 return (result);
5908
5909 isc_nonce_buf(view->secret, sizeof(view->secret));
5910
5911 ISC_LIST_APPEND(*viewlist, view, link);
5912 dns_view_attach(view, viewp);
5913 return (ISC_R_SUCCESS);
5914}
5915
5916/*
5917 * Configure or reconfigure a zone.
5918 */
5919static isc_result_t
5920configure_zone(const cfg_obj_t *config, const cfg_obj_t *zconfig,
5921 const cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
5922 dns_viewlist_t *viewlist, cfg_aclconfctx_t *aclconf,
5923 bool added, bool old_rpz_ok,
5924 bool modify)
5925{
5926 dns_view_t *pview = NULL; /* Production view */
5927 dns_zone_t *zone = NULL; /* New or reused zone */
5928 dns_zone_t *raw = NULL; /* New or reused raw zone */
5929 dns_zone_t *dupzone = NULL;
5930 const cfg_obj_t *options = NULL;
5931 const cfg_obj_t *zoptions = NULL;
5932 const cfg_obj_t *typeobj = NULL;
5933 const cfg_obj_t *forwarders = NULL;
5934 const cfg_obj_t *forwardtype = NULL;
5935 const cfg_obj_t *ixfrfromdiffs = NULL;
5936 const cfg_obj_t *only = NULL;
5937 const cfg_obj_t *signing = NULL;
5938 const cfg_obj_t *viewobj = NULL;
5939 isc_result_t result;
5940 isc_result_t tresult;
5941 isc_buffer_t buffer;
5942 dns_fixedname_t fixorigin;
5943 dns_name_t *origin;
5944 const char *zname;
5945 dns_rdataclass_t zclass;
5946 const char *ztypestr;
5947 dns_rpz_num_t rpz_num;
5948 bool zone_is_catz = false;
5949
5950 options = NULL;
5951 (void)cfg_map_get(config, "options", &options);
5952
5953 zoptions = cfg_tuple_get(zconfig, "options");
5954
5955 /*
5956 * Get the zone origin as a dns_name_t.
5957 */
5958 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
5959 isc_buffer_constinit(&buffer, zname, strlen(zname));
5960 isc_buffer_add(&buffer, strlen(zname));
5961 dns_fixedname_init(&fixorigin);
5962 CHECK(dns_name_fromtext(dns_fixedname_name(&fixorigin),
5963 &buffer, dns_rootname, 0, NULL));
5964 origin = dns_fixedname_name(&fixorigin);
5965
5966 CHECK(named_config_getclass(cfg_tuple_get(zconfig, "class"),
5967 view->rdclass, &zclass));
5968 if (zclass != view->rdclass) {
5969 const char *vname = NULL;
5970 if (vconfig != NULL)
5971 vname = cfg_obj_asstring(cfg_tuple_get(vconfig,
5972 "name"));
5973 else
5974 vname = "<default view>";
5975
5976 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
5977 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
5978 "zone '%s': wrong class for view '%s'",
5979 zname, vname);
5980 result = ISC_R_FAILURE;
5981 goto cleanup;
5982 }
5983
5984 (void)cfg_map_get(zoptions, "in-view", &viewobj);
5985 if (viewobj != NULL) {
5986 const char *inview = cfg_obj_asstring(viewobj);
5987 dns_view_t *otherview = NULL;
5988
5989 if (viewlist == NULL) {
5990 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
5991 "'in-view' option is not permitted in "
5992 "dynamically added zones");
5993 result = ISC_R_FAILURE;
5994 goto cleanup;
5995 }
5996
5997 result = dns_viewlist_find(viewlist, inview, view->rdclass,
5998 &otherview);
5999 if (result != ISC_R_SUCCESS) {
6000 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6001 "view '%s' is not yet defined.", inview);
6002 result = ISC_R_FAILURE;
6003 goto cleanup;
6004 }
6005
6006 result = dns_view_findzone(otherview, origin, &zone);
6007 dns_view_detach(&otherview);
6008 if (result != ISC_R_SUCCESS) {
6009 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6010 "zone '%s' not defined in view '%s'",
6011 zname, inview);
6012 result = ISC_R_FAILURE;
6013 goto cleanup;
6014 }
6015
6016 CHECK(dns_view_addzone(view, zone));
6017 dns_zone_detach(&zone);
6018
6019 /*
6020 * If the zone contains a 'forwarders' statement, configure
6021 * selective forwarding. Note: this is not inherited from the
6022 * other view.
6023 */
6024 forwarders = NULL;
6025 result = cfg_map_get(zoptions, "forwarders", &forwarders);
6026 if (result == ISC_R_SUCCESS) {
6027 forwardtype = NULL;
6028 (void)cfg_map_get(zoptions, "forward", &forwardtype);
6029 CHECK(configure_forward(config, view, origin,
6030 forwarders, forwardtype));
6031 }
6032 result = ISC_R_SUCCESS;
6033 goto cleanup;
6034 }
6035
6036 (void)cfg_map_get(zoptions, "type", &typeobj);
6037 if (typeobj == NULL) {
6038 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6039 "zone '%s' 'type' not specified", zname);
6040 result = ISC_R_FAILURE;
6041 goto cleanup;
6042 }
6043 ztypestr = cfg_obj_asstring(typeobj);
6044
6045 /*
6046 * "hints zones" aren't zones. If we've got one,
6047 * configure it and return.
6048 */
6049 if (strcasecmp(ztypestr, "hint") == 0) {
6050 const cfg_obj_t *fileobj = NULL;
6051 if (cfg_map_get(zoptions, "file", &fileobj) != ISC_R_SUCCESS) {
6052 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6053 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6054 "zone '%s': 'file' not specified",
6055 zname);
6056 result = ISC_R_FAILURE;
6057 goto cleanup;
6058 }
6059 if (dns_name_equal(origin, dns_rootname)) {
6060 const char *hintsfile = cfg_obj_asstring(fileobj);
6061
6062 CHECK(configure_hints(view, hintsfile));
6063
6064 /*
6065 * Hint zones may also refer to delegation only points.
6066 */
6067 only = NULL;
6068 tresult = cfg_map_get(zoptions, "delegation-only",
6069 &only);
6070 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6071 CHECK(dns_view_adddelegationonly(view, origin));
6072 } else {
6073 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6074 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6075 "ignoring non-root hint zone '%s'",
6076 zname);
6077 result = ISC_R_SUCCESS;
6078 }
6079 /* Skip ordinary zone processing. */
6080 goto cleanup;
6081 }
6082
6083 /*
6084 * "forward zones" aren't zones either. Translate this syntax into
6085 * the appropriate selective forwarding configuration and return.
6086 */
6087 if (strcasecmp(ztypestr, "forward") == 0) {
6088 forwardtype = NULL;
6089 forwarders = NULL;
6090
6091 (void)cfg_map_get(zoptions, "forward", &forwardtype);
6092 (void)cfg_map_get(zoptions, "forwarders", &forwarders);
6093 CHECK(configure_forward(config, view, origin, forwarders,
6094 forwardtype));
6095
6096 /*
6097 * Forward zones may also set delegation only.
6098 */
6099 only = NULL;
6100 tresult = cfg_map_get(zoptions, "delegation-only", &only);
6101 if (tresult == ISC_R_SUCCESS && cfg_obj_asboolean(only))
6102 CHECK(dns_view_adddelegationonly(view, origin));
6103 goto cleanup;
6104 }
6105
6106 /*
6107 * "delegation-only zones" aren't zones either.
6108 */
6109 if (strcasecmp(ztypestr, "delegation-only") == 0) {
6110 result = dns_view_adddelegationonly(view, origin);
6111 goto cleanup;
6112 }
6113
6114 /*
6115 * Redirect zones only require minimal configuration.
6116 */
6117 if (strcasecmp(ztypestr, "redirect") == 0) {
6118 if (view->redirect != NULL) {
6119 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6120 "redirect zone already exists");
6121 result = ISC_R_EXISTS;
6122 goto cleanup;
6123 }
6124 result = dns_viewlist_find(viewlist, view->name,
6125 view->rdclass, &pview);
6126 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
6127 goto cleanup;
6128 if (pview != NULL && pview->redirect != NULL) {
6129 dns_zone_attach(pview->redirect, &zone);
6130 dns_zone_setview(zone, view);
6131 } else {
6132 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr,
6133 &zone));
6134 CHECK(dns_zone_setorigin(zone, origin));
6135 dns_zone_setview(zone, view);
6136 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr,
6137 zone));
6138 dns_zone_setstats(zone, named_g_server->zonestats);
6139 }
6140 CHECK(named_zone_configure(config, vconfig, zconfig,
6141 aclconf, zone, NULL));
6142 dns_zone_attach(zone, &view->redirect);
6143 goto cleanup;
6144 }
6145
6146 if (!modify) {
6147 /*
6148 * Check for duplicates in the new zone table.
6149 */
6150 result = dns_view_findzone(view, origin, &dupzone);
6151 if (result == ISC_R_SUCCESS) {
6152 /*
6153 * We already have this zone!
6154 */
6155 cfg_obj_log(zconfig, named_g_lctx, ISC_LOG_ERROR,
6156 "zone '%s' already exists", zname);
6157 dns_zone_detach(&dupzone);
6158 result = ISC_R_EXISTS;
6159 goto cleanup;
6160 }
6161 INSIST(dupzone == NULL);
6162 }
6163
6164 /*
6165 * Note whether this is a response policy zone and which one if so,
6166 * unless we are using RPZ service interface. In that case, the
6167 * BIND zone database has nothing to do with rpz and so we don't care.
6168 */
6169 for (rpz_num = 0; ; ++rpz_num) {
6170 if (view->rpzs == NULL || rpz_num >= view->rpzs->p.num_zones ||
6171 view->rpzs->p.dnsrps_enabled)
6172 {
6173 rpz_num = DNS_RPZ_INVALID_NUM;
6174 break;
6175 }
6176 if (dns_name_equal(&view->rpzs->zones[rpz_num]->origin, origin))
6177 break;
6178 }
6179
6180 if (view->catzs != NULL &&
6181 dns_catz_get_zone(view->catzs, origin) != NULL)
6182 zone_is_catz = true;
6183
6184 /*
6185 * See if we can reuse an existing zone. This is
6186 * only possible if all of these are true:
6187 * - The zone's view exists
6188 * - A zone with the right name exists in the view
6189 * - The zone is compatible with the config
6190 * options (e.g., an existing master zone cannot
6191 * be reused if the options specify a slave zone)
6192 * - The zone was not and is still not a response policy zone
6193 * or the zone is a policy zone with an unchanged number
6194 * and we are using the old policy zone summary data.
6195 */
6196 result = dns_viewlist_find(&named_g_server->viewlist, view->name,
6197 view->rdclass, &pview);
6198 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
6199 goto cleanup;
6200 if (pview != NULL)
6201 result = dns_view_findzone(pview, origin, &zone);
6202 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS)
6203 goto cleanup;
6204
6205 if (zone != NULL && !named_zone_reusable(zone, zconfig))
6206 dns_zone_detach(&zone);
6207
6208 if (zone != NULL && (rpz_num != dns_zone_get_rpz_num(zone) ||
6209 (rpz_num != DNS_RPZ_INVALID_NUM && !old_rpz_ok)))
6210 dns_zone_detach(&zone);
6211
6212 if (zone != NULL) {
6213 /*
6214 * We found a reusable zone. Make it use the
6215 * new view.
6216 */
6217 dns_zone_setview(zone, view);
6218 } else {
6219 /*
6220 * We cannot reuse an existing zone, we have
6221 * to create a new one.
6222 */
6223 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6224 CHECK(dns_zone_setorigin(zone, origin));
6225 dns_zone_setview(zone, view);
6226 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6227 dns_zone_setstats(zone, named_g_server->zonestats);
6228 }
6229 if (rpz_num != DNS_RPZ_INVALID_NUM) {
6230 result = dns_zone_rpz_enable(zone, view->rpzs, rpz_num);
6231 if (result != ISC_R_SUCCESS) {
6232 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6233 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6234 "zone '%s': incompatible"
6235 " masterfile-format or database"
6236 " for a response policy zone",
6237 zname);
6238 goto cleanup;
6239 }
6240 }
6241
6242 if (zone_is_catz)
6243 dns_zone_catz_enable(zone, view->catzs);
6244
6245 /*
6246 * If the zone contains a 'forwarders' statement, configure
6247 * selective forwarding.
6248 */
6249 forwarders = NULL;
6250 if (cfg_map_get(zoptions, "forwarders", &forwarders) == ISC_R_SUCCESS)
6251 {
6252 forwardtype = NULL;
6253 (void)cfg_map_get(zoptions, "forward", &forwardtype);
6254 CHECK(configure_forward(config, view, origin, forwarders,
6255 forwardtype));
6256 }
6257
6258 /*
6259 * Stub and forward zones may also refer to delegation only points.
6260 */
6261 only = NULL;
6262 if (cfg_map_get(zoptions, "delegation-only", &only) == ISC_R_SUCCESS)
6263 {
6264 if (cfg_obj_asboolean(only))
6265 CHECK(dns_view_adddelegationonly(view, origin));
6266 }
6267
6268 /*
6269 * Mark whether the zone was originally added at runtime or not
6270 */
6271 dns_zone_setadded(zone, added);
6272
6273 signing = NULL;
6274 if ((strcasecmp(ztypestr, "primary") == 0 ||
6275 strcasecmp(ztypestr, "master") == 0 ||
6276 strcasecmp(ztypestr, "secondary") == 0 ||
6277 strcasecmp(ztypestr, "slave") == 0) &&
6278 cfg_map_get(zoptions, "inline-signing", &signing) == ISC_R_SUCCESS &&
6279 cfg_obj_asboolean(signing))
6280 {
6281 dns_zone_getraw(zone, &raw);
6282 if (raw == NULL) {
6283 CHECK(dns_zone_create(&raw, mctx));
6284 CHECK(dns_zone_setorigin(raw, origin));
6285 dns_zone_setview(raw, view);
6286 dns_zone_setstats(raw, named_g_server->zonestats);
6287 CHECK(dns_zone_link(zone, raw));
6288 }
6289 if (cfg_map_get(zoptions, "ixfr-from-differences",
6290 &ixfrfromdiffs) == ISC_R_SUCCESS)
6291 {
6292 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6293 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6294 "zone '%s': 'ixfr-from-differences' is "
6295 "ignored for inline-signed zones",
6296 zname);
6297 }
6298 }
6299
6300 /*
6301 * Configure the zone.
6302 */
6303 CHECK(named_zone_configure(config, vconfig, zconfig,
6304 aclconf, zone, raw));
6305
6306 /*
6307 * Add the zone to its view in the new view list.
6308 */
6309 if (!modify)
6310 CHECK(dns_view_addzone(view, zone));
6311
6312 if (zone_is_catz) {
6313 /*
6314 * force catz reload if the zone is loaded;
6315 * if it's not it'll get reloaded on zone load
6316 */
6317 dns_db_t *db = NULL;
6318
6319 tresult = dns_zone_getdb(zone, &db);
6320 if (tresult == ISC_R_SUCCESS) {
6321 dns_catz_dbupdate_callback(db, view->catzs);
6322 dns_db_detach(&db);
6323 }
6324
6325 }
6326
6327 /*
6328 * Ensure that zone keys are reloaded on reconfig
6329 */
6330 if ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0)
6331 dns_zone_rekey(zone, false);
6332
6333 cleanup:
6334 if (zone != NULL)
6335 dns_zone_detach(&zone);
6336 if (raw != NULL)
6337 dns_zone_detach(&raw);
6338 if (pview != NULL)
6339 dns_view_detach(&pview);
6340
6341 return (result);
6342}
6343
6344/*
6345 * Configure built-in zone for storing managed-key data.
6346 */
6347static isc_result_t
6348add_keydata_zone(dns_view_t *view, const char *directory, isc_mem_t *mctx) {
6349 isc_result_t result;
6350 dns_view_t *pview = NULL;
6351 dns_zone_t *zone = NULL;
6352 dns_acl_t *none = NULL;
6353 char filename[PATH_MAX];
6354 bool defaultview;
6355
6356 REQUIRE(view != NULL);
6357
6358 /* See if we can re-use an existing keydata zone. */
6359 result = dns_viewlist_find(&named_g_server->viewlist,
6360 view->name, view->rdclass, &pview);
6361 if (result != ISC_R_NOTFOUND && result != ISC_R_SUCCESS) {
6362 return (result);
6363 }
6364
6365 if (pview != NULL) {
6366 if (pview->managed_keys != NULL) {
6367 dns_zone_attach(pview->managed_keys,
6368 &view->managed_keys);
6369 dns_zone_setview(pview->managed_keys, view);
6370 dns_view_detach(&pview);
6371 dns_zone_synckeyzone(view->managed_keys);
6372 return (ISC_R_SUCCESS);
6373 }
6374
6375 dns_view_detach(&pview);
6376 }
6377
6378 /* No existing keydata zone was found; create one */
6379 CHECK(dns_zonemgr_createzone(named_g_server->zonemgr, &zone));
6380 CHECK(dns_zone_setorigin(zone, dns_rootname));
6381
6382 defaultview = (strcmp(view->name, "_default") == 0);
6383 CHECK(isc_file_sanitize(directory,
6384 defaultview ? "managed-keys" : view->name,
6385 defaultview ? "bind" : "mkeys",
6386 filename, sizeof(filename)));
6387 CHECK(dns_zone_setfile(zone, filename, dns_masterformat_text,
6388 &dns_master_style_default));
6389
6390 dns_zone_setview(zone, view);
6391 dns_zone_settype(zone, dns_zone_key);
6392 dns_zone_setclass(zone, view->rdclass);
6393
6394 CHECK(dns_zonemgr_managezone(named_g_server->zonemgr, zone));
6395
6396 CHECK(dns_acl_none(mctx, &none));
6397 dns_zone_setqueryacl(zone, none);
6398 dns_zone_setqueryonacl(zone, none);
6399 dns_acl_detach(&none);
6400
6401 dns_zone_setdialup(zone, dns_dialuptype_no);
6402 dns_zone_setnotifytype(zone, dns_notifytype_no);
6403 dns_zone_setoption(zone, DNS_ZONEOPT_NOCHECKNS, true);
6404 dns_zone_setjournalsize(zone, 0);
6405
6406 dns_zone_setstats(zone, named_g_server->zonestats);
6407 CHECK(setquerystats(zone, mctx, dns_zonestat_none));
6408
6409 if (view->managed_keys != NULL) {
6410 dns_zone_detach(&view->managed_keys);
6411 }
6412 dns_zone_attach(zone, &view->managed_keys);
6413
6414 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6415 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6416 "set up managed keys zone for view %s, file '%s'",
6417 view->name, filename);
6418
6419cleanup:
6420 if (zone != NULL) {
6421 dns_zone_detach(&zone);
6422 }
6423 if (none != NULL) {
6424 dns_acl_detach(&none);
6425 }
6426
6427 return (result);
6428}
6429
6430/*
6431 * Configure a single server quota.
6432 */
6433static void
6434configure_server_quota(const cfg_obj_t **maps, const char *name,
6435 isc_quota_t *quota)
6436{
6437 const cfg_obj_t *obj = NULL;
6438 isc_result_t result;
6439
6440 result = named_config_get(maps, name, &obj);
6441 INSIST(result == ISC_R_SUCCESS);
6442 isc_quota_max(quota, cfg_obj_asuint32(obj));
6443}
6444
6445/*
6446 * This function is called as soon as the 'directory' statement has been
6447 * parsed. This can be extended to support other options if necessary.
6448 */
6449static isc_result_t
6450directory_callback(const char *clausename, const cfg_obj_t *obj, void *arg) {
6451 isc_result_t result;
6452 const char *directory;
6453
6454 REQUIRE(strcasecmp("directory", clausename) == 0);
6455
6456 UNUSED(arg);
6457 UNUSED(clausename);
6458
6459 /*
6460 * Change directory.
6461 */
6462 directory = cfg_obj_asstring(obj);
6463
6464 if (! isc_file_ischdiridempotent(directory))
6465 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
6466 "option 'directory' contains relative path '%s'",
6467 directory);
6468
6469#if 0
6470 if (!isc_file_isdirwritable(directory)) {
6471 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6472 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
6473 "directory '%s' is not writable",
6474 directory);
6475 return (ISC_R_NOPERM);
6476 }
6477#endif
6478
6479 result = isc_dir_chdir(directory);
6480 if (result != ISC_R_SUCCESS) {
6481 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR,
6482 "change directory to '%s' failed: %s",
6483 directory, isc_result_totext(result));
6484 return (result);
6485 }
6486
6487 return (ISC_R_SUCCESS);
6488}
6489
6490static isc_result_t
6491add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr,
6492 isc_dscp_t dscp, bool wcardport_ok)
6493{
6494 ns_listenelt_t *lelt = NULL;
6495 dns_acl_t *src_acl = NULL;
6496 isc_result_t result;
6497 isc_sockaddr_t any_sa6;
6498 isc_netaddr_t netaddr;
6499
6500 REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
6501
6502 isc_sockaddr_any6(&any_sa6);
6503 if (!isc_sockaddr_equal(&any_sa6, addr) &&
6504 (wcardport_ok || isc_sockaddr_getport(addr) != 0)) {
6505 isc_netaddr_fromin6(&netaddr, &addr->type.sin6.sin6_addr);
6506
6507 result = dns_acl_create(mctx, 0, &src_acl);
6508 if (result != ISC_R_SUCCESS)
6509 return (result);
6510
6511 result = dns_iptable_addprefix(src_acl->iptable, &netaddr,
6512 128, true);
6513 if (result != ISC_R_SUCCESS)
6514 goto clean;
6515
6516 result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
6517 dscp, src_acl, &lelt);
6518 if (result != ISC_R_SUCCESS)
6519 goto clean;
6520 ISC_LIST_APPEND(list->elts, lelt, link);
6521 }
6522
6523 return (ISC_R_SUCCESS);
6524
6525 clean:
6526 INSIST(lelt == NULL);
6527 dns_acl_detach(&src_acl);
6528
6529 return (result);
6530}
6531
6532/*
6533 * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
6534 * to update the listening interfaces accordingly.
6535 * We currently only consider IPv6, because this only affects IPv6 wildcard
6536 * sockets.
6537 */
6538static void
6539adjust_interfaces(named_server_t *server, isc_mem_t *mctx) {
6540 isc_result_t result;
6541 ns_listenlist_t *list = NULL;
6542 dns_view_t *view;
6543 dns_zone_t *zone, *next;
6544 isc_sockaddr_t addr, *addrp;
6545 isc_dscp_t dscp = -1;
6546
6547 result = ns_listenlist_create(mctx, &list);
6548 if (result != ISC_R_SUCCESS)
6549 return;
6550
6551 for (view = ISC_LIST_HEAD(server->viewlist);
6552 view != NULL;
6553 view = ISC_LIST_NEXT(view, link)) {
6554 dns_dispatch_t *dispatch6;
6555
6556 dispatch6 = dns_resolver_dispatchv6(view->resolver);
6557 if (dispatch6 == NULL)
6558 continue;
6559 result = dns_dispatch_getlocaladdress(dispatch6, &addr);
6560 if (result != ISC_R_SUCCESS)
6561 goto fail;
6562
6563 /*
6564 * We always add non-wildcard address regardless of whether
6565 * the port is 'any' (the fourth arg is TRUE): if the port is
6566 * specific, we need to add it since it may conflict with a
6567 * listening interface; if it's zero, we'll dynamically open
6568 * query ports, and some of them may override an existing
6569 * wildcard IPv6 port.
6570 */
6571 /* XXXMPA fix dscp */
6572 result = add_listenelt(mctx, list, &addr, dscp, true);
6573 if (result != ISC_R_SUCCESS)
6574 goto fail;
6575 }
6576
6577 zone = NULL;
6578 for (result = dns_zone_first(server->zonemgr, &zone);
6579 result == ISC_R_SUCCESS;
6580 next = NULL, result = dns_zone_next(zone, &next), zone = next) {
6581 dns_view_t *zoneview;
6582
6583 /*
6584 * At this point the zone list may contain a stale zone
6585 * just removed from the configuration. To see the validity,
6586 * check if the corresponding view is in our current view list.
6587 * There may also be old zones that are still in the process
6588 * of shutting down and have detached from their old view
6589 * (zoneview == NULL).
6590 */
6591 zoneview = dns_zone_getview(zone);
6592 if (zoneview == NULL)
6593 continue;
6594 for (view = ISC_LIST_HEAD(server->viewlist);
6595 view != NULL && view != zoneview;
6596 view = ISC_LIST_NEXT(view, link))
6597 ;
6598 if (view == NULL)
6599 continue;
6600
6601 addrp = dns_zone_getnotifysrc6(zone);
6602 dscp = dns_zone_getnotifysrc6dscp(zone);
6603 result = add_listenelt(mctx, list, addrp, dscp, false);
6604 if (result != ISC_R_SUCCESS)
6605 goto fail;
6606
6607 addrp = dns_zone_getxfrsource6(zone);
6608 dscp = dns_zone_getxfrsource6dscp(zone);
6609 result = add_listenelt(mctx, list, addrp, dscp, false);
6610 if (result != ISC_R_SUCCESS)
6611 goto fail;
6612 }
6613
6614 ns_interfacemgr_adjust(server->interfacemgr, list, true);
6615
6616 clean:
6617 ns_listenlist_detach(&list);
6618 return;
6619
6620 fail:
6621 /*
6622 * Even when we failed the procedure, most of other interfaces
6623 * should work correctly. We therefore just warn it.
6624 */
6625 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6626 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
6627 "could not adjust the listen-on list; "
6628 "some interfaces may not work");
6629 goto clean;
6630}
6631
6632/*
6633 * This event callback is invoked to do periodic network interface
6634 * scanning.
6635 */
6636
6637static void
6638interface_timer_tick(isc_task_t *task, isc_event_t *event) {
6639 named_server_t *server = (named_server_t *) event->ev_arg;
6640 INSIST(task == server->task);
6641 UNUSED(task);
6642
6643 isc_event_free(&event);
6644 ns_interfacemgr_scan(server->interfacemgr, false);
6645}
6646
6647static void
6648heartbeat_timer_tick(isc_task_t *task, isc_event_t *event) {
6649 named_server_t *server = (named_server_t *) event->ev_arg;
6650 dns_view_t *view;
6651
6652 UNUSED(task);
6653 isc_event_free(&event);
6654 view = ISC_LIST_HEAD(server->viewlist);
6655 while (view != NULL) {
6656 dns_view_dialup(view);
6657 view = ISC_LIST_NEXT(view, link);
6658 }
6659}
6660
6661typedef struct {
6662 isc_mem_t *mctx;
6663 isc_task_t *task;
6664 dns_rdataset_t rdataset;
6665 dns_rdataset_t sigrdataset;
6666 dns_fetch_t *fetch;
6667} ns_tat_t;
6668
6669static int
6670cid(const void *a, const void *b) {
6671 const uint16_t ida = *(const uint16_t *)a;
6672 const uint16_t idb = *(const uint16_t *)b;
6673 if (ida < idb)
6674 return (-1);
6675 else if (ida > idb)
6676 return (1);
6677 else
6678 return (0);
6679}
6680
6681static void
6682tat_done(isc_task_t *task, isc_event_t *event) {
6683 dns_fetchevent_t *devent;
6684 ns_tat_t *tat;
6685
6686 UNUSED(task);
6687 INSIST(event != NULL && event->ev_type == DNS_EVENT_FETCHDONE);
6688 INSIST(event->ev_arg != NULL);
6689
6690 tat = event->ev_arg;
6691 devent = (dns_fetchevent_t *) event;
6692
6693 /* Free resources which are not of interest */
6694 if (devent->node != NULL)
6695 dns_db_detachnode(devent->db, &devent->node);
6696 if (devent->db != NULL)
6697 dns_db_detach(&devent->db);
6698 isc_event_free(&event);
6699 dns_resolver_destroyfetch(&tat->fetch);
6700 if (dns_rdataset_isassociated(&tat->rdataset))
6701 dns_rdataset_disassociate(&tat->rdataset);
6702 if (dns_rdataset_isassociated(&tat->sigrdataset))
6703 dns_rdataset_disassociate(&tat->sigrdataset);
6704 isc_task_detach(&tat->task);
6705 isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
6706}
6707
6708struct dotat_arg {
6709 dns_view_t *view;
6710 isc_task_t *task;
6711};
6712
6713/*%
6714 * Prepare the QNAME for the TAT query to be sent by processing the trust
6715 * anchors present at 'keynode' of 'keytable'. Store the result in 'dst' and
6716 * the domain name which 'keynode' is associated with in 'origin'.
6717 *
6718 * A maximum of 12 key IDs can be reported in a single TAT query due to the
6719 * 63-octet length limit for any single label in a domain name. If there are
6720 * more than 12 keys configured at 'keynode', only the first 12 will be
6721 * reported in the TAT query.
6722 */
6723static isc_result_t
6724get_tat_qname(dns_name_t *dst, const dns_name_t **origin,
6725 dns_keytable_t *keytable, dns_keynode_t *keynode)
6726{
6727 dns_keynode_t *firstnode = keynode;
6728 dns_keynode_t *nextnode;
6729 unsigned int i, n = 0;
6730 uint16_t ids[12];
6731 isc_textregion_t r;
6732 char label[64];
6733 int m;
6734
6735 REQUIRE(origin != NULL && *origin == NULL);
6736
6737 do {
6738 dst_key_t *key = dns_keynode_key(keynode);
6739 if (key != NULL) {
6740 *origin = dst_key_name(key);
6741 if (n < (sizeof(ids)/sizeof(ids[0]))) {
6742 ids[n] = dst_key_id(key);
6743 n++;
6744 }
6745 }
6746 nextnode = NULL;
6747 (void)dns_keytable_nextkeynode(keytable, keynode, &nextnode);
6748 if (keynode != firstnode) {
6749 dns_keytable_detachkeynode(keytable, &keynode);
6750 }
6751 keynode = nextnode;
6752 } while (keynode != NULL);
6753
6754 if (n == 0) {
6755 return (DNS_R_EMPTYNAME);
6756 }
6757
6758 if (n > 1) {
6759 qsort(ids, n, sizeof(ids[0]), cid);
6760 }
6761
6762 /*
6763 * Encoded as "_ta-xxxx\(-xxxx\)*" where xxxx is the hex version of
6764 * of the keyid.
6765 */
6766 label[0] = 0;
6767 r.base = label;
6768 r.length = sizeof(label);
6769 m = snprintf(r.base, r.length, "_ta");
6770 if (m < 0 || (unsigned)m > r.length) {
6771 return (ISC_R_FAILURE);
6772 }
6773 isc_textregion_consume(&r, m);
6774 for (i = 0; i < n; i++) {
6775 m = snprintf(r.base, r.length, "-%04x", ids[i]);
6776 if (m < 0 || (unsigned)m > r.length) {
6777 return (ISC_R_FAILURE);
6778 }
6779 isc_textregion_consume(&r, m);
6780 }
6781
6782 return (dns_name_fromstring2(dst, label, *origin, 0, NULL));
6783}
6784
6785static void
6786dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) {
6787 struct dotat_arg *dotat_arg = arg;
6788 char namebuf[DNS_NAME_FORMATSIZE];
6789 const dns_name_t *origin = NULL;
6790 dns_fixedname_t fixed, fdomain;
6791 dns_name_t *tatname, *domain;
6792 dns_rdataset_t nameservers;
6793 isc_result_t result;
6794 dns_view_t *view;
6795 isc_task_t *task;
6796 ns_tat_t *tat;
6797
6798 REQUIRE(keytable != NULL);
6799 REQUIRE(keynode != NULL);
6800 REQUIRE(arg != NULL);
6801
6802 view = dotat_arg->view;
6803 task = dotat_arg->task;
6804
6805 tatname = dns_fixedname_initname(&fixed);
6806 result = get_tat_qname(tatname, &origin, keytable, keynode);
6807 if (result != ISC_R_SUCCESS) {
6808 return;
6809 }
6810
6811 dns_name_format(tatname, namebuf, sizeof(namebuf));
6812 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
6813 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
6814 "%s: sending trust-anchor-telemetry query '%s/NULL'",
6815 view->name, namebuf);
6816
6817 tat = isc_mem_get(dotat_arg->view->mctx, sizeof(*tat));
6818 if (tat == NULL) {
6819 return;
6820 }
6821
6822 tat->mctx = NULL;
6823 tat->task = NULL;
6824 tat->fetch = NULL;
6825 dns_rdataset_init(&tat->rdataset);
6826 dns_rdataset_init(&tat->sigrdataset);
6827 isc_mem_attach(dotat_arg->view->mctx, &tat->mctx);
6828 isc_task_attach(task, &tat->task);
6829
6830 /*
6831 * TAT queries should be sent to the authoritative servers for a given
6832 * zone. If this function is called for a keytable node corresponding
6833 * to a locally served zone, calling dns_resolver_createfetch() with
6834 * NULL 'domain' and 'nameservers' arguments will cause 'tatname' to be
6835 * resolved locally, without sending any TAT queries upstream.
6836 *
6837 * Work around this issue by calling dns_view_findzonecut() first. If
6838 * the zone is served locally, the NS RRset for the given domain name
6839 * will be retrieved from local data; if it is not, the deepest zone
6840 * cut we have for it will be retrieved from cache. In either case,
6841 * passing the results to dns_resolver_createfetch() will prevent it
6842 * from returning NXDOMAIN for 'tatname' while still allowing it to
6843 * chase down any potential delegations returned by upstream servers in
6844 * order to eventually find the destination host to send the TAT query
6845 * to.
6846 *
6847 * 'origin' holds the domain name at 'keynode', i.e. the domain name
6848 * for which the trust anchors to be reported by this TAT query are
6849 * defined.
6850 *
6851 * After the dns_view_findzonecut() call, 'domain' will hold the
6852 * deepest zone cut we can find for 'origin' while 'nameservers' will
6853 * hold the NS RRset at that zone cut.
6854 */
6855 domain = dns_fixedname_initname(&fdomain);
6856 dns_rdataset_init(&nameservers);
6857 result = dns_view_findzonecut(view, origin, domain, NULL, 0, 0,
6858 true, true, &nameservers, NULL);
6859 if (result == ISC_R_SUCCESS) {
6860 result = dns_resolver_createfetch(view->resolver, tatname,
6861 dns_rdatatype_null, domain,
6862 &nameservers, NULL, NULL, 0,
6863 0, 0, NULL, tat->task,
6864 tat_done, tat,
6865 &tat->rdataset,
6866 &tat->sigrdataset,
6867 &tat->fetch);
6868 }
6869
6870 /*
6871 * 'domain' holds the dns_name_t pointer inside a dst_key_t structure.
6872 * dns_resolver_createfetch() creates its own copy of 'domain' if it
6873 * succeeds. Thus, 'domain' is not freed here.
6874 *
6875 * Even if dns_view_findzonecut() returned something else than
6876 * ISC_R_SUCCESS, it still could have associated 'nameservers'.
6877 * dns_resolver_createfetch() creates its own copy of 'nameservers' if
6878 * it succeeds. Thus, we need to check whether 'nameservers' is
6879 * associated and release it if it is.
6880 */
6881 if (dns_rdataset_isassociated(&nameservers)) {
6882 dns_rdataset_disassociate(&nameservers);
6883 }
6884
6885 if (result != ISC_R_SUCCESS) {
6886 isc_task_detach(&tat->task);
6887 isc_mem_putanddetach(&tat->mctx, tat, sizeof(*tat));
6888 }
6889}
6890
6891static void
6892tat_timer_tick(isc_task_t *task, isc_event_t *event) {
6893 isc_result_t result;
6894 named_server_t *server = (named_server_t *) event->ev_arg;
6895 struct dotat_arg arg;
6896 dns_view_t *view;
6897 dns_keytable_t *secroots = NULL;
6898
6899 isc_event_free(&event);
6900
6901 for (view = ISC_LIST_HEAD(server->viewlist);
6902 view != NULL;
6903 view = ISC_LIST_NEXT(view, link))
6904 {
6905 if (!view->trust_anchor_telemetry ||
6906 !view->enablevalidation)
6907 {
6908 continue;
6909 }
6910
6911 result = dns_view_getsecroots(view, &secroots);
6912 if (result != ISC_R_SUCCESS) {
6913 continue;
6914 }
6915
6916 arg.view = view;
6917 arg.task = task;
6918 (void)dns_keytable_forall(secroots, dotat, &arg);
6919 dns_keytable_detach(&secroots);
6920 }
6921}
6922
6923static void
6924pps_timer_tick(isc_task_t *task, isc_event_t *event) {
6925 static unsigned int oldrequests = 0;
6926 unsigned int requests = ns_client_requests;
6927
6928 UNUSED(task);
6929 isc_event_free(&event);
6930
6931 /*
6932 * Don't worry about wrapping as the overflow result will be right.
6933 */
6934 dns_pps = (requests - oldrequests) / 1200;
6935 oldrequests = requests;
6936}
6937
6938/*
6939 * Replace the current value of '*field', a dynamically allocated
6940 * string or NULL, with a dynamically allocated copy of the
6941 * null-terminated string pointed to by 'value', or NULL.
6942 */
6943static isc_result_t
6944setstring(named_server_t *server, char **field, const char *value) {
6945 char *copy;
6946
6947 if (value != NULL) {
6948 copy = isc_mem_strdup(server->mctx, value);
6949 if (copy == NULL)
6950 return (ISC_R_NOMEMORY);
6951 } else {
6952 copy = NULL;
6953 }
6954
6955 if (*field != NULL)
6956 isc_mem_free(server->mctx, *field);
6957
6958 *field = copy;
6959 return (ISC_R_SUCCESS);
6960}
6961
6962/*
6963 * Replace the current value of '*field', a dynamically allocated
6964 * string or NULL, with another dynamically allocated string
6965 * or NULL if whether 'obj' is a string or void value, respectively.
6966 */
6967static isc_result_t
6968setoptstring(named_server_t *server, char **field, const cfg_obj_t *obj) {
6969 if (cfg_obj_isvoid(obj))
6970 return (setstring(server, field, NULL));
6971 else
6972 return (setstring(server, field, cfg_obj_asstring(obj)));
6973}
6974
6975static void
6976set_limit(const cfg_obj_t **maps, const char *configname,
6977 const char *description, isc_resource_t resourceid,
6978 isc_resourcevalue_t defaultvalue)
6979{
6980 const cfg_obj_t *obj = NULL;
6981 const char *resource;
6982 isc_resourcevalue_t value;
6983 isc_result_t result;
6984
6985 if (named_config_get(maps, configname, &obj) != ISC_R_SUCCESS)
6986 return;
6987
6988 if (cfg_obj_isstring(obj)) {
6989 resource = cfg_obj_asstring(obj);
6990 if (strcasecmp(resource, "unlimited") == 0)
6991 value = ISC_RESOURCE_UNLIMITED;
6992 else {
6993 INSIST(strcasecmp(resource, "default") == 0);
6994 value = defaultvalue;
6995 }
6996 } else
6997 value = cfg_obj_asuint64(obj);
6998
6999 result = isc_resource_setlimit(resourceid, value);
7000 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7001 NAMED_LOGMODULE_SERVER,
7002 result == ISC_R_SUCCESS ?
7003 ISC_LOG_DEBUG(3) : ISC_LOG_WARNING,
7004 "set maximum %s to %" PRIu64 ": %s",
7005 description, value, isc_result_totext(result));
7006}
7007
7008#define SETLIMIT(cfgvar, resource, description) \
7009 set_limit(maps, cfgvar, description, isc_resource_ ## resource, \
7010 named_g_init ## resource)
7011
7012static void
7013set_limits(const cfg_obj_t **maps) {
7014 SETLIMIT("stacksize", stacksize, "stack size");
7015 SETLIMIT("datasize", datasize, "data size");
7016 SETLIMIT("coresize", coresize, "core size");
7017 SETLIMIT("files", openfiles, "open files");
7018}
7019
7020static void
7021portset_fromconf(isc_portset_t *portset, const cfg_obj_t *ports,
7022 bool positive)
7023{
7024 const cfg_listelt_t *element;
7025
7026 for (element = cfg_list_first(ports);
7027 element != NULL;
7028 element = cfg_list_next(element)) {
7029 const cfg_obj_t *obj = cfg_listelt_value(element);
7030
7031 if (cfg_obj_isuint32(obj)) {
7032 in_port_t port = (in_port_t)cfg_obj_asuint32(obj);
7033
7034 if (positive)
7035 isc_portset_add(portset, port);
7036 else
7037 isc_portset_remove(portset, port);
7038 } else {
7039 const cfg_obj_t *obj_loport, *obj_hiport;
7040 in_port_t loport, hiport;
7041
7042 obj_loport = cfg_tuple_get(obj, "loport");
7043 loport = (in_port_t)cfg_obj_asuint32(obj_loport);
7044 obj_hiport = cfg_tuple_get(obj, "hiport");
7045 hiport = (in_port_t)cfg_obj_asuint32(obj_hiport);
7046
7047 if (positive)
7048 isc_portset_addrange(portset, loport, hiport);
7049 else {
7050 isc_portset_removerange(portset, loport,
7051 hiport);
7052 }
7053 }
7054 }
7055}
7056
7057static isc_result_t
7058removed(dns_zone_t *zone, void *uap) {
7059 const char *type;
7060
7061 if (dns_zone_getview(zone) != uap)
7062 return (ISC_R_SUCCESS);
7063
7064 switch (dns_zone_gettype(zone)) {
7065 case dns_zone_master:
7066 type = "master";
7067 break;
7068 case dns_zone_slave:
7069 type = "slave";
7070 break;
7071 case dns_zone_mirror:
7072 type = "mirror";
7073 break;
7074 case dns_zone_stub:
7075 type = "stub";
7076 break;
7077 case dns_zone_staticstub:
7078 type = "static-stub";
7079 break;
7080 case dns_zone_redirect:
7081 type = "redirect";
7082 break;
7083 default:
7084 type = "other";
7085 break;
7086 }
7087 dns_zone_log(zone, ISC_LOG_INFO, "(%s) removed", type);
7088 return (ISC_R_SUCCESS);
7089}
7090
7091static void
7092cleanup_session_key(named_server_t *server, isc_mem_t *mctx) {
7093 if (server->session_keyfile != NULL) {
7094 isc_file_remove(server->session_keyfile);
7095 isc_mem_free(mctx, server->session_keyfile);
7096 server->session_keyfile = NULL;
7097 }
7098
7099 if (server->session_keyname != NULL) {
7100 if (dns_name_dynamic(server->session_keyname))
7101 dns_name_free(server->session_keyname, mctx);
7102 isc_mem_put(mctx, server->session_keyname, sizeof(dns_name_t));
7103 server->session_keyname = NULL;
7104 }
7105
7106 if (server->sessionkey != NULL)
7107 dns_tsigkey_detach(&server->sessionkey);
7108
7109 server->session_keyalg = DST_ALG_UNKNOWN;
7110 server->session_keybits = 0;
7111}
7112
7113static isc_result_t
7114generate_session_key(const char *filename, const char *keynamestr,
7115 const dns_name_t *keyname, const char *algstr,
7116 const dns_name_t *algname, unsigned int algtype,
7117 uint16_t bits, isc_mem_t *mctx,
7118 dns_tsigkey_t **tsigkeyp)
7119{
7120 isc_result_t result = ISC_R_SUCCESS;
7121 dst_key_t *key = NULL;
7122 isc_buffer_t key_txtbuffer;
7123 isc_buffer_t key_rawbuffer;
7124 char key_txtsecret[256];
7125 char key_rawsecret[64];
7126 isc_region_t key_rawregion;
7127 isc_stdtime_t now;
7128 dns_tsigkey_t *tsigkey = NULL;
7129 FILE *fp = NULL;
7130
7131 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7132 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7133 "generating session key for dynamic DNS");
7134
7135 /* generate key */
7136 result = dst_key_generate(keyname, algtype, bits, 1, 0,
7137 DNS_KEYPROTO_ANY, dns_rdataclass_in,
7138 mctx, &key, NULL);
7139 if (result != ISC_R_SUCCESS)
7140 return (result);
7141
7142 /*
7143 * Dump the key to the buffer for later use. Should be done before
7144 * we transfer the ownership of key to tsigkey.
7145 */
7146 isc_buffer_init(&key_rawbuffer, &key_rawsecret, sizeof(key_rawsecret));
7147 CHECK(dst_key_tobuffer(key, &key_rawbuffer));
7148
7149 isc_buffer_usedregion(&key_rawbuffer, &key_rawregion);
7150 isc_buffer_init(&key_txtbuffer, &key_txtsecret, sizeof(key_txtsecret));
7151 CHECK(isc_base64_totext(&key_rawregion, -1, "", &key_txtbuffer));
7152
7153 /* Store the key in tsigkey. */
7154 isc_stdtime_get(&now);
7155 CHECK(dns_tsigkey_createfromkey(dst_key_name(key), algname, key,
7156 false, NULL, now, now, mctx, NULL,
7157 &tsigkey));
7158
7159 /* Dump the key to the key file. */
7160 fp = named_os_openfile(filename, S_IRUSR|S_IWUSR, true);
7161 if (fp == NULL) {
7162 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7163 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7164 "could not create %s", filename);
7165 result = ISC_R_NOPERM;
7166 goto cleanup;
7167 }
7168
7169 fprintf(fp, "key \"%s\" {\n"
7170 "\talgorithm %s;\n"
7171 "\tsecret \"%.*s\";\n};\n", keynamestr, algstr,
7172 (int) isc_buffer_usedlength(&key_txtbuffer),
7173 (char*) isc_buffer_base(&key_txtbuffer));
7174
7175 CHECK(isc_stdio_flush(fp));
7176 result = isc_stdio_close(fp);
7177 fp = NULL;
7178 if (result != ISC_R_SUCCESS)
7179 goto cleanup;
7180
7181 dst_key_free(&key);
7182
7183 *tsigkeyp = tsigkey;
7184
7185 return (ISC_R_SUCCESS);
7186
7187 cleanup:
7188 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7189 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7190 "failed to generate session key "
7191 "for dynamic DNS: %s", isc_result_totext(result));
7192 if (fp != NULL) {
7193 (void)isc_stdio_close(fp);
7194 (void)isc_file_remove(filename);
7195 }
7196 if (tsigkey != NULL)
7197 dns_tsigkey_detach(&tsigkey);
7198 if (key != NULL)
7199 dst_key_free(&key);
7200
7201 return (result);
7202}
7203
7204static isc_result_t
7205configure_session_key(const cfg_obj_t **maps, named_server_t *server,
7206 isc_mem_t *mctx)
7207{
7208 const char *keyfile, *keynamestr, *algstr;
7209 unsigned int algtype;
7210 dns_fixedname_t fname;
7211 dns_name_t *keyname;
7212 const dns_name_t *algname;
7213 isc_buffer_t buffer;
7214 uint16_t bits;
7215 const cfg_obj_t *obj;
7216 bool need_deleteold = false;
7217 bool need_createnew = false;
7218 isc_result_t result;
7219
7220 obj = NULL;
7221 result = named_config_get(maps, "session-keyfile", &obj);
7222 if (result == ISC_R_SUCCESS) {
7223 if (cfg_obj_isvoid(obj))
7224 keyfile = NULL; /* disable it */
7225 else
7226 keyfile = cfg_obj_asstring(obj);
7227 } else
7228 keyfile = named_g_defaultsessionkeyfile;
7229
7230 obj = NULL;
7231 result = named_config_get(maps, "session-keyname", &obj);
7232 INSIST(result == ISC_R_SUCCESS);
7233 keynamestr = cfg_obj_asstring(obj);
7234 isc_buffer_constinit(&buffer, keynamestr, strlen(keynamestr));
7235 isc_buffer_add(&buffer, strlen(keynamestr));
7236 keyname = dns_fixedname_initname(&fname);
7237 result = dns_name_fromtext(keyname, &buffer, dns_rootname, 0, NULL);
7238 if (result != ISC_R_SUCCESS)
7239 return (result);
7240
7241 obj = NULL;
7242 result = named_config_get(maps, "session-keyalg", &obj);
7243 INSIST(result == ISC_R_SUCCESS);
7244 algstr = cfg_obj_asstring(obj);
7245 algname = NULL;
7246 result = named_config_getkeyalgorithm2(algstr, &algname, &algtype,
7247 &bits);
7248 if (result != ISC_R_SUCCESS) {
7249 const char *s = " (keeping current key)";
7250
7251 cfg_obj_log(obj, named_g_lctx, ISC_LOG_ERROR, "session-keyalg: "
7252 "unsupported or unknown algorithm '%s'%s",
7253 algstr,
7254 server->session_keyfile != NULL ? s : "");
7255 return (result);
7256 }
7257
7258 /* See if we need to (re)generate a new key. */
7259 if (keyfile == NULL) {
7260 if (server->session_keyfile != NULL)
7261 need_deleteold = true;
7262 } else if (server->session_keyfile == NULL)
7263 need_createnew = true;
7264 else if (strcmp(keyfile, server->session_keyfile) != 0 ||
7265 !dns_name_equal(server->session_keyname, keyname) ||
7266 server->session_keyalg != algtype ||
7267 server->session_keybits != bits) {
7268 need_deleteold = true;
7269 need_createnew = true;
7270 }
7271
7272 if (need_deleteold) {
7273 INSIST(server->session_keyfile != NULL);
7274 INSIST(server->session_keyname != NULL);
7275 INSIST(server->sessionkey != NULL);
7276
7277 cleanup_session_key(server, mctx);
7278 }
7279
7280 if (need_createnew) {
7281 INSIST(server->sessionkey == NULL);
7282 INSIST(server->session_keyfile == NULL);
7283 INSIST(server->session_keyname == NULL);
7284 INSIST(server->session_keyalg == DST_ALG_UNKNOWN);
7285 INSIST(server->session_keybits == 0);
7286
7287 server->session_keyname = isc_mem_get(mctx, sizeof(dns_name_t));
7288 if (server->session_keyname == NULL)
7289 goto cleanup;
7290 dns_name_init(server->session_keyname, NULL);
7291 CHECK(dns_name_dup(keyname, mctx, server->session_keyname));
7292
7293 server->session_keyfile = isc_mem_strdup(mctx, keyfile);
7294 if (server->session_keyfile == NULL)
7295 goto cleanup;
7296
7297 server->session_keyalg = algtype;
7298 server->session_keybits = bits;
7299
7300 CHECK(generate_session_key(keyfile, keynamestr, keyname, algstr,
7301 algname, algtype, bits, mctx,
7302 &server->sessionkey));
7303 }
7304
7305 return (result);
7306
7307 cleanup:
7308 cleanup_session_key(server, mctx);
7309 return (result);
7310}
7311
7312#ifndef HAVE_LMDB
7313static isc_result_t
7314count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7315 isc_result_t result;
7316
7317 /* The new zone file may not exist. That is OK. */
7318 if (!isc_file_exists(view->new_zone_file)) {
7319 *num_zonesp = 0;
7320 return (ISC_R_SUCCESS);
7321 }
7322
7323 /*
7324 * In the case of NZF files, we also parse the configuration in
7325 * the file at this stage.
7326 *
7327 * This may be called in multiple views, so we reset
7328 * the parser each time.
7329 */
7330 cfg_parser_reset(named_g_addparser);
7331 result = cfg_parse_file(named_g_addparser, view->new_zone_file,
7332 &cfg_type_addzoneconf, &nzcfg->nzf_config);
7333 if (result == ISC_R_SUCCESS) {
7334 int num_zones;
7335
7336 num_zones = count_zones(nzcfg->nzf_config);
7337 isc_log_write(named_g_lctx,
7338 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7339 ISC_LOG_INFO,
7340 "NZF file '%s' contains %d zones",
7341 view->new_zone_file, num_zones);
7342 if (num_zonesp != NULL)
7343 *num_zonesp = num_zones;
7344 } else {
7345 isc_log_write(named_g_lctx,
7346 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7347 ISC_LOG_ERROR,
7348 "Error parsing NZF file '%s': %s",
7349 view->new_zone_file,
7350 isc_result_totext(result));
7351 }
7352
7353 return (result);
7354}
7355
7356#else /* HAVE_LMDB */
7357
7358static isc_result_t
7359count_newzones(dns_view_t *view, ns_cfgctx_t *nzcfg, int *num_zonesp) {
7360 isc_result_t result;
7361 int n;
7362
7363 UNUSED(nzcfg);
7364
7365 REQUIRE(num_zonesp != NULL);
7366
7367 CHECK(migrate_nzf(view));
7368
7369 isc_log_write(named_g_lctx,
7370 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7371 ISC_LOG_INFO, "loading NZD zone count from '%s' "
7372 "for view '%s'",
7373 view->new_zone_db, view->name);
7374
7375 CHECK(nzd_count(view, &n));
7376
7377 *num_zonesp = n;
7378
7379 isc_log_write(named_g_lctx,
7380 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7381 ISC_LOG_INFO,
7382 "NZD database '%s' contains %d zones",
7383 view->new_zone_db, n);
7384
7385 cleanup:
7386 if (result != ISC_R_SUCCESS)
7387 *num_zonesp = 0;
7388
7389 return (ISC_R_SUCCESS);
7390}
7391
7392#endif /* HAVE_LMDB */
7393
7394static isc_result_t
7395setup_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7396 cfg_parser_t *conf_parser, cfg_aclconfctx_t *actx,
7397 int *num_zones)
7398{
7399 isc_result_t result = ISC_R_SUCCESS;
7400 bool allow = false;
7401 ns_cfgctx_t *nzcfg = NULL;
7402 const cfg_obj_t *maps[4];
7403 const cfg_obj_t *options = NULL, *voptions = NULL;
7404 const cfg_obj_t *nz = NULL;
7405 const cfg_obj_t *nzdir = NULL;
7406 const char *dir = NULL;
7407 const cfg_obj_t *obj = NULL;
7408 int i = 0;
7409 uint64_t mapsize = 0ULL;
7410
7411 REQUIRE(config != NULL);
7412
7413 if (vconfig != NULL)
7414 voptions = cfg_tuple_get(vconfig, "options");
7415 if (voptions != NULL)
7416 maps[i++] = voptions;
7417 result = cfg_map_get(config, "options", &options);
7418 if (result == ISC_R_SUCCESS)
7419 maps[i++] = options;
7420 maps[i++] = named_g_defaults;
7421 maps[i] = NULL;
7422
7423 result = named_config_get(maps, "allow-new-zones", &nz);
7424 if (result == ISC_R_SUCCESS)
7425 allow = cfg_obj_asboolean(nz);
7426 result = named_config_get(maps, "new-zones-directory", &nzdir);
7427 if (result == ISC_R_SUCCESS) {
7428 dir = cfg_obj_asstring(nzdir);
7429 if (dir != NULL) {
7430 result = isc_file_isdirectory(dir);
7431 }
7432 if (result != ISC_R_SUCCESS) {
7433 isc_log_write(named_g_lctx, DNS_LOGCATEGORY_SECURITY,
7434 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7435 "invalid new-zones-directory %s: %s",
7436 dir, isc_result_totext(result));
7437 return (result);
7438 }
7439 if (!isc_file_isdirwritable(dir)) {
7440 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7441 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7442 "new-zones-directory '%s' "
7443 "is not writable", dir);
7444 return (ISC_R_NOPERM);
7445 }
7446
7447 dns_view_setnewzonedir(view, dir);
7448 }
7449
7450#ifdef HAVE_LMDB
7451 result = named_config_get(maps, "lmdb-mapsize", &obj);
7452 if (result == ISC_R_SUCCESS && obj != NULL) {
7453 mapsize = cfg_obj_asuint64(obj);
7454 if (mapsize < (1ULL << 20)) { /* 1 megabyte */
7455 cfg_obj_log(obj, named_g_lctx,
7456 ISC_LOG_ERROR,
7457 "'lmdb-mapsize "
7458 "%" PRId64 "' "
7459 "is too small",
7460 mapsize);
7461 return (ISC_R_FAILURE);
7462 } else if (mapsize > (1ULL << 40)) { /* 1 terabyte */
7463 cfg_obj_log(obj, named_g_lctx,
7464 ISC_LOG_ERROR,
7465 "'lmdb-mapsize "
7466 "%" PRId64 "' "
7467 "is too large",
7468 mapsize);
7469 return (ISC_R_FAILURE);
7470 }
7471 }
7472#else
7473 UNUSED(obj);
7474#endif /* HAVE_LMDB */
7475
7476 /*
7477 * A non-empty catalog-zones statement implies allow-new-zones
7478 */
7479 if (!allow) {
7480 const cfg_obj_t *cz = NULL;
7481 result = named_config_get(maps, "catalog-zones", &cz);
7482 if (result == ISC_R_SUCCESS) {
7483 const cfg_listelt_t *e =
7484 cfg_list_first(cfg_tuple_get(cz, "zone list"));
7485 if (e != NULL)
7486 allow = true;
7487 }
7488 }
7489
7490 if (!allow) {
7491 dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7492 if (num_zones != NULL)
7493 *num_zones = 0;
7494 return (ISC_R_SUCCESS);
7495 }
7496
7497 nzcfg = isc_mem_get(view->mctx, sizeof(*nzcfg));
7498 if (nzcfg == NULL) {
7499 dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7500 return (ISC_R_NOMEMORY);
7501 }
7502
7503 /*
7504 * We attach the parser that was used for config as well
7505 * as the one that will be used for added zones, to avoid
7506 * a shutdown race later.
7507 */
7508 memset(nzcfg, 0, sizeof(*nzcfg));
7509 cfg_parser_attach(conf_parser, &nzcfg->conf_parser);
7510 cfg_parser_attach(named_g_addparser, &nzcfg->add_parser);
7511 isc_mem_attach(view->mctx, &nzcfg->mctx);
7512 cfg_aclconfctx_attach(actx, &nzcfg->actx);
7513
7514 result = dns_view_setnewzones(view, true, nzcfg,
7515 newzone_cfgctx_destroy, mapsize);
7516 if (result != ISC_R_SUCCESS) {
7517 dns_view_setnewzones(view, false, NULL, NULL, 0ULL);
7518 return (result);
7519 }
7520
7521 cfg_obj_attach(config, &nzcfg->config);
7522 if (vconfig != NULL)
7523 cfg_obj_attach(vconfig, &nzcfg->vconfig);
7524
7525 result = count_newzones(view, nzcfg, num_zones);
7526 return (result);
7527}
7528
7529static void
7530configure_zone_setviewcommit(isc_result_t result, const cfg_obj_t *zconfig,
7531 dns_view_t *view)
7532{
7533 const char *zname;
7534 dns_fixedname_t fixorigin;
7535 dns_name_t *origin;
7536 isc_result_t result2;
7537 dns_view_t *pview = NULL;
7538 dns_zone_t *zone = NULL;
7539 dns_zone_t *raw = NULL;
7540
7541 zname = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
7542 origin = dns_fixedname_initname(&fixorigin);
7543
7544 result2 = dns_name_fromstring(origin, zname, 0, NULL);
7545 if (result2 != ISC_R_SUCCESS) {
7546 return;
7547 }
7548
7549 result2 = dns_viewlist_find(&named_g_server->viewlist, view->name,
7550 view->rdclass, &pview);
7551 if (result2 != ISC_R_SUCCESS) {
7552 return;
7553 }
7554
7555 result2 = dns_view_findzone(pview, origin, &zone);
7556 if (result2 != ISC_R_SUCCESS) {
7557 dns_view_detach(&pview);
7558 return;
7559 }
7560
7561 dns_zone_getraw(zone, &raw);
7562
7563 if (result == ISC_R_SUCCESS) {
7564 dns_zone_setviewcommit(zone);
7565 if (raw != NULL)
7566 dns_zone_setviewcommit(raw);
7567 } else {
7568 dns_zone_setviewrevert(zone);
7569 if (raw != NULL)
7570 dns_zone_setviewrevert(raw);
7571 }
7572
7573 if (raw != NULL) {
7574 dns_zone_detach(&raw);
7575 }
7576
7577 dns_zone_detach(&zone);
7578 dns_view_detach(&pview);
7579}
7580
7581#ifndef HAVE_LMDB
7582
7583static isc_result_t
7584configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7585 isc_mem_t *mctx, cfg_aclconfctx_t *actx)
7586{
7587 isc_result_t result;
7588 ns_cfgctx_t *nzctx;
7589 const cfg_obj_t *zonelist;
7590 const cfg_listelt_t *element;
7591
7592 nzctx = view->new_zone_config;
7593 if (nzctx == NULL || nzctx->nzf_config == NULL) {
7594 return (ISC_R_SUCCESS);
7595 }
7596
7597 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7598 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
7599 "loading additional zones for view '%s'",
7600 view->name);
7601
7602 zonelist = NULL;
7603 cfg_map_get(nzctx->nzf_config, "zone", &zonelist);
7604
7605 for (element = cfg_list_first(zonelist);
7606 element != NULL;
7607 element = cfg_list_next(element))
7608 {
7609 const cfg_obj_t *zconfig = cfg_listelt_value(element);
7610 CHECK(configure_zone(config, zconfig, vconfig, mctx,
7611 view, &named_g_server->viewlist, actx,
7612 true, false, false));
7613 }
7614
7615 result = ISC_R_SUCCESS;
7616
7617 cleanup:
7618 for (element = cfg_list_first(zonelist);
7619 element != NULL;
7620 element = cfg_list_next(element))
7621 {
7622 const cfg_obj_t *zconfig = cfg_listelt_value(element);
7623 configure_zone_setviewcommit(result, zconfig, view);
7624 }
7625
7626 return (result);
7627}
7628
7629#else /* HAVE_LMDB */
7630
7631static isc_result_t
7632data_to_cfg(dns_view_t *view, MDB_val *key, MDB_val *data,
7633 isc_buffer_t **text, cfg_obj_t **zoneconfig)
7634{
7635 isc_result_t result;
7636 const char *zone_name;
7637 size_t zone_name_len;
7638 const char *zone_config;
7639 size_t zone_config_len;
7640 cfg_obj_t *zoneconf = NULL;
7641
7642 REQUIRE(view != NULL);
7643 REQUIRE(key != NULL);
7644 REQUIRE(data != NULL);
7645 REQUIRE(text != NULL);
7646 REQUIRE(zoneconfig != NULL && *zoneconfig == NULL);
7647
7648 if (*text == NULL) {
7649 result = isc_buffer_allocate(view->mctx, text, 256);
7650 if (result != ISC_R_SUCCESS)
7651 goto cleanup;
7652 } else {
7653 isc_buffer_clear(*text);
7654 }
7655
7656 zone_name = (const char *) key->mv_data;
7657 zone_name_len = key->mv_size;
7658 INSIST(zone_name != NULL && zone_name_len > 0);
7659
7660 zone_config = (const char *) data->mv_data;
7661 zone_config_len = data->mv_size;
7662 INSIST(zone_config != NULL && zone_config_len > 0);
7663
7664 /* zone zonename { config; }; */
7665 result = isc_buffer_reserve(text, 5 + zone_name_len + 1 +
7666 zone_config_len + 2);
7667 if (result != ISC_R_SUCCESS) {
7668 goto cleanup;
7669 }
7670
7671 CHECK(putstr(text, "zone "));
7672 CHECK(putmem(text, (const void *) zone_name, zone_name_len));
7673 CHECK(putstr(text, " "));
7674 CHECK(putmem(text, (const void *) zone_config, zone_config_len));
7675 CHECK(putstr(text, ";\n"));
7676
7677 cfg_parser_reset(named_g_addparser);
7678 result = cfg_parse_buffer(named_g_addparser, *text, zone_name, 0,
7679 &cfg_type_addzoneconf, 0, &zoneconf);
7680 if (result != ISC_R_SUCCESS) {
7681 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7682 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
7683 "parsing config for zone '%.*s' in "
7684 "NZD database '%s' failed",
7685 (int) zone_name_len, zone_name,
7686 view->new_zone_db);
7687 goto cleanup;
7688 }
7689
7690 *zoneconfig = zoneconf;
7691 zoneconf = NULL;
7692 result = ISC_R_SUCCESS;
7693
7694 cleanup:
7695 if (zoneconf != NULL) {
7696 cfg_obj_destroy(named_g_addparser, &zoneconf);
7697 }
7698
7699 return (result);
7700}
7701
7702/*%
7703 * Prototype for a callback which can be used with for_all_newzone_cfgs().
7704 */
7705typedef isc_result_t (*newzone_cfg_cb_t)(const cfg_obj_t *zconfig,
7706 cfg_obj_t *config, cfg_obj_t *vconfig,
7707 isc_mem_t *mctx, dns_view_t *view,
7708 cfg_aclconfctx_t *actx);
7709
7710/*%
7711 * For each zone found in a NZD opened by the caller, create an object
7712 * representing its configuration and invoke "callback" with the created
7713 * object, "config", "vconfig", "mctx", "view" and "actx" as arguments (all
7714 * these are non-global variables required to invoke configure_zone()).
7715 * Immediately interrupt processing if an error is encountered while
7716 * transforming NZD data into a zone configuration object or if "callback"
7717 * returns an error.
7718 */
7719static isc_result_t
7720for_all_newzone_cfgs(newzone_cfg_cb_t callback, cfg_obj_t *config,
7721 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
7722 cfg_aclconfctx_t *actx, MDB_txn *txn, MDB_dbi dbi)
7723{
7724 const cfg_obj_t *zconfig, *zlist;
7725 isc_result_t result = ISC_R_SUCCESS;
7726 cfg_obj_t *zconfigobj = NULL;
7727 isc_buffer_t *text = NULL;
7728 MDB_cursor *cursor = NULL;
7729 MDB_val data, key;
7730 int status;
7731
7732 status = mdb_cursor_open(txn, dbi, &cursor);
7733 if (status != MDB_SUCCESS) {
7734 return (ISC_R_FAILURE);
7735 }
7736
7737 for (status = mdb_cursor_get(cursor, &key, &data, MDB_FIRST);
7738 status == MDB_SUCCESS;
7739 status = mdb_cursor_get(cursor, &key, &data, MDB_NEXT))
7740 {
7741 /*
7742 * Create a configuration object from data fetched from NZD.
7743 */
7744 result = data_to_cfg(view, &key, &data, &text, &zconfigobj);
7745 if (result != ISC_R_SUCCESS) {
7746 break;
7747 }
7748
7749 /*
7750 * Extract zone configuration from configuration object.
7751 */
7752 zlist = NULL;
7753 result = cfg_map_get(zconfigobj, "zone", &zlist);
7754 if (result != ISC_R_SUCCESS) {
7755 break;
7756 } else if (!cfg_obj_islist(zlist)) {
7757 result = ISC_R_FAILURE;
7758 break;
7759 }
7760 zconfig = cfg_listelt_value(cfg_list_first(zlist));
7761
7762 /*
7763 * Invoke callback.
7764 */
7765 result = callback(zconfig, config, vconfig, mctx, view, actx);
7766 if (result != ISC_R_SUCCESS) {
7767 break;
7768 }
7769
7770 /*
7771 * Destroy the configuration object created in this iteration.
7772 */
7773 cfg_obj_destroy(named_g_addparser, &zconfigobj);
7774 }
7775
7776 if (text != NULL) {
7777 isc_buffer_free(&text);
7778 }
7779 if (zconfigobj != NULL) {
7780 cfg_obj_destroy(named_g_addparser, &zconfigobj);
7781 }
7782 mdb_cursor_close(cursor);
7783
7784 return (result);
7785}
7786
7787/*%
7788 * Attempt to configure a zone found in NZD and return the result.
7789 */
7790static isc_result_t
7791configure_newzone(const cfg_obj_t *zconfig, cfg_obj_t *config,
7792 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
7793 cfg_aclconfctx_t *actx)
7794{
7795 return (configure_zone(config, zconfig, vconfig, mctx, view,
7796 &named_g_server->viewlist, actx, true,
7797 false, false));
7798}
7799
7800/*%
7801 * Revert new view assignment for a zone found in NZD.
7802 */
7803static isc_result_t
7804configure_newzone_revert(const cfg_obj_t *zconfig, cfg_obj_t *config,
7805 cfg_obj_t *vconfig, isc_mem_t *mctx, dns_view_t *view,
7806 cfg_aclconfctx_t *actx)
7807{
7808 UNUSED(config);
7809 UNUSED(vconfig);
7810 UNUSED(mctx);
7811 UNUSED(actx);
7812
7813 configure_zone_setviewcommit(ISC_R_FAILURE, zconfig, view);
7814
7815 return (ISC_R_SUCCESS);
7816}
7817
7818static isc_result_t
7819configure_newzones(dns_view_t *view, cfg_obj_t *config, cfg_obj_t *vconfig,
7820 isc_mem_t *mctx, cfg_aclconfctx_t *actx)
7821{
7822 isc_result_t result;
7823 MDB_txn *txn = NULL;
7824 MDB_dbi dbi;
7825
7826 if (view->new_zone_config == NULL) {
7827 return (ISC_R_SUCCESS);
7828 }
7829
7830 result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
7831 if (result != ISC_R_SUCCESS) {
7832 return (ISC_R_SUCCESS);
7833 }
7834
7835 isc_log_write(named_g_lctx,
7836 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7837 ISC_LOG_INFO, "loading NZD configs from '%s' "
7838 "for view '%s'",
7839 view->new_zone_db, view->name);
7840
7841 result = for_all_newzone_cfgs(configure_newzone, config, vconfig, mctx,
7842 view, actx, txn, dbi);
7843 if (result != ISC_R_SUCCESS) {
7844 /*
7845 * An error was encountered while attempting to configure zones
7846 * found in NZD. As this error may have been caused by a
7847 * configure_zone() failure, try restoring a sane configuration
7848 * by reattaching all zones found in NZD to the old view. If
7849 * this also fails, too bad, there is nothing more we can do in
7850 * terms of trying to make things right.
7851 */
7852 (void) for_all_newzone_cfgs(configure_newzone_revert, config,
7853 vconfig, mctx, view, actx, txn,
7854 dbi);
7855 }
7856
7857 (void) nzd_close(&txn, false);
7858 return (result);
7859}
7860
7861static isc_result_t
7862get_newzone_config(dns_view_t *view, const char *zonename,
7863 cfg_obj_t **zoneconfig)
7864{
7865 isc_result_t result;
7866 int status;
7867 cfg_obj_t *zoneconf = NULL;
7868 isc_buffer_t *text = NULL;
7869 MDB_txn *txn = NULL;
7870 MDB_dbi dbi;
7871 MDB_val key, data;
7872 char zname[DNS_NAME_FORMATSIZE];
7873 dns_fixedname_t fname;
7874 dns_name_t *name;
7875 isc_buffer_t b;
7876
7877 INSIST(zoneconfig != NULL && *zoneconfig == NULL);
7878
7879 CHECK(nzd_open(view, MDB_RDONLY, &txn, &dbi));
7880
7881 isc_log_write(named_g_lctx,
7882 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
7883 ISC_LOG_INFO, "loading NZD config from '%s' "
7884 "for zone '%s'",
7885 view->new_zone_db, zonename);
7886
7887 /* Normalize zone name */
7888 isc_buffer_constinit(&b, zonename, strlen(zonename));
7889 isc_buffer_add(&b, strlen(zonename));
7890 name = dns_fixedname_initname(&fname);
7891 CHECK(dns_name_fromtext(name, &b, dns_rootname,
7892 DNS_NAME_DOWNCASE, NULL));
7893 dns_name_format(name, zname, sizeof(zname));
7894
7895 key.mv_data = zname;
7896 key.mv_size = strlen(zname);
7897
7898 status = mdb_get(txn, dbi, &key, &data);
7899 if (status != MDB_SUCCESS) {
7900 CHECK(ISC_R_FAILURE);
7901 }
7902
7903 CHECK(data_to_cfg(view, &key, &data, &text, &zoneconf));
7904
7905 *zoneconfig = zoneconf;
7906 zoneconf = NULL;
7907 result = ISC_R_SUCCESS;
7908
7909 cleanup:
7910 (void) nzd_close(&txn, false);
7911
7912 if (zoneconf != NULL) {
7913 cfg_obj_destroy(named_g_addparser, &zoneconf);
7914 }
7915 if (text != NULL) {
7916 isc_buffer_free(&text);
7917 }
7918
7919 return (result);
7920}
7921
7922#endif /* HAVE_LMDB */
7923
7924static int
7925count_zones(const cfg_obj_t *conf) {
7926 const cfg_obj_t *zonelist = NULL;
7927 const cfg_listelt_t *element;
7928 int n = 0;
7929
7930 REQUIRE(conf != NULL);
7931
7932 cfg_map_get(conf, "zone", &zonelist);
7933 for (element = cfg_list_first(zonelist);
7934 element != NULL;
7935 element = cfg_list_next(element))
7936 n++;
7937
7938 return (n);
7939}
7940
7941static isc_result_t
7942check_lockfile(named_server_t *server, const cfg_obj_t *config,
7943 bool first_time)
7944{
7945 isc_result_t result;
7946 const char *filename = NULL;
7947 const cfg_obj_t *maps[3];
7948 const cfg_obj_t *options;
7949 const cfg_obj_t *obj;
7950 int i;
7951
7952 i = 0;
7953 options = NULL;
7954 result = cfg_map_get(config, "options", &options);
7955 if (result == ISC_R_SUCCESS)
7956 maps[i++] = options;
7957 maps[i++] = named_g_defaults;
7958 maps[i] = NULL;
7959
7960 obj = NULL;
7961 (void) named_config_get(maps, "lock-file", &obj);
7962
7963 if (!first_time) {
7964 if (obj != NULL && !cfg_obj_isstring(obj) &&
7965 server->lockfile != NULL &&
7966 strcmp(cfg_obj_asstring(obj), server->lockfile) != 0)
7967 isc_log_write(named_g_lctx,
7968 NAMED_LOGCATEGORY_GENERAL,
7969 NAMED_LOGMODULE_SERVER,
7970 ISC_LOG_WARNING,
7971 "changing 'lock-file' "
7972 "has no effect until the "
7973 "server is restarted");
7974
7975 return (ISC_R_SUCCESS);
7976 }
7977
7978 if (obj != NULL) {
7979 if (cfg_obj_isvoid(obj)) {
7980 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7981 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
7982 "skipping lock-file check ");
7983 return (ISC_R_SUCCESS);
7984 } else if (named_g_forcelock) {
7985 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
7986 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
7987 "'lock-file' has no effect "
7988 "because the server was run with -X");
7989 server->lockfile = isc_mem_strdup(server->mctx,
7990 named_g_defaultlockfile);
7991 } else {
7992 filename = cfg_obj_asstring(obj);
7993 server->lockfile = isc_mem_strdup(server->mctx,
7994 filename);
7995 }
7996
7997 if (server->lockfile == NULL)
7998 return (ISC_R_NOMEMORY);
7999 }
8000
8001 if (named_g_forcelock && named_g_defaultlockfile != NULL) {
8002 INSIST(server->lockfile == NULL);
8003 server->lockfile = isc_mem_strdup(server->mctx,
8004 named_g_defaultlockfile);
8005 }
8006
8007 if (server->lockfile == NULL)
8008 return (ISC_R_SUCCESS);
8009
8010 if (named_os_issingleton(server->lockfile))
8011 return (ISC_R_SUCCESS);
8012
8013 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8014 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8015 "could not lock %s; another named "
8016 "process may be running", server->lockfile);
8017 return (ISC_R_FAILURE);
8018}
8019
8020static isc_result_t
8021load_configuration(const char *filename, named_server_t *server,
8022 bool first_time)
8023{
8024 cfg_obj_t *config = NULL, *bindkeys = NULL;
8025 cfg_parser_t *conf_parser = NULL, *bindkeys_parser = NULL;
8026 const cfg_listelt_t *element;
8027 const cfg_obj_t *builtin_views;
8028 const cfg_obj_t *maps[3];
8029 const cfg_obj_t *obj;
8030 const cfg_obj_t *options;
8031 const cfg_obj_t *usev4ports, *avoidv4ports, *usev6ports, *avoidv6ports;
8032 const cfg_obj_t *views;
8033 dns_view_t *view = NULL;
8034 dns_view_t *view_next;
8035 dns_viewlist_t tmpviewlist;
8036 dns_viewlist_t viewlist, builtin_viewlist;
8037 in_port_t listen_port, udpport_low, udpport_high;
8038 int i, backlog;
8039 int num_zones = 0;
8040 bool exclusive = false;
8041 isc_interval_t interval;
8042 isc_logconfig_t *logc = NULL;
8043 isc_portset_t *v4portset = NULL;
8044 isc_portset_t *v6portset = NULL;
8045 isc_resourcevalue_t nfiles;
8046 isc_result_t result, tresult;
8047 uint32_t heartbeat_interval;
8048 uint32_t interface_interval;
8049 uint32_t reserved;
8050 uint32_t udpsize;
8051 uint32_t transfer_message_size;
8052 named_cache_t *nsc;
8053 named_cachelist_t cachelist, tmpcachelist;
8054 ns_altsecret_t *altsecret;
8055 ns_altsecretlist_t altsecrets, tmpaltsecrets;
8056 unsigned int maxsocks;
8057 uint32_t softquota = 0;
8058 uint32_t max;
8059 unsigned int initial, idle, keepalive, advertised;
8060 dns_aclenv_t *env =
8061 ns_interfacemgr_getaclenv(named_g_server->interfacemgr);
8062
8063 ISC_LIST_INIT(viewlist);
8064 ISC_LIST_INIT(builtin_viewlist);
8065 ISC_LIST_INIT(cachelist);
8066 ISC_LIST_INIT(altsecrets);
8067
8068 /* Create the ACL configuration context */
8069 if (named_g_aclconfctx != NULL) {
8070 cfg_aclconfctx_detach(&named_g_aclconfctx);
8071 }
8072 CHECK(cfg_aclconfctx_create(named_g_mctx, &named_g_aclconfctx));
8073
8074 /*
8075 * Shut down all dyndb instances.
8076 */
8077 dns_dyndb_cleanup(false);
8078
8079 /*
8080 * Parse the global default pseudo-config file.
8081 */
8082 if (first_time) {
8083 result = named_config_parsedefaults(named_g_parser,
8084 &named_g_config);
8085 if (result != ISC_R_SUCCESS) {
8086 named_main_earlyfatal("unable to load "
8087 "internal defaults: %s",
8088 isc_result_totext(result));
8089 }
8090 RUNTIME_CHECK(cfg_map_get(named_g_config, "options",
8091 &named_g_defaults) == ISC_R_SUCCESS);
8092 }
8093
8094 /*
8095 * Parse the configuration file using the new config code.
8096 */
8097 config = NULL;
8098 isc_log_write(named_g_lctx,
8099 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
8100 ISC_LOG_INFO, "loading configuration from '%s'",
8101 filename);
8102 CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8103 &conf_parser));
8104 cfg_parser_setcallback(conf_parser, directory_callback, NULL);
8105 result = cfg_parse_file(conf_parser, filename,
8106 &cfg_type_namedconf, &config);
8107
8108 CHECK(result);
8109
8110 /*
8111 * Check the validity of the configuration.
8112 *
8113 * (Ignore plugin parameters for now; they will be
8114 * checked later when the modules are actually loaded and
8115 * registered.)
8116 */
8117 CHECK(bind9_check_namedconf(config, false, named_g_lctx, named_g_mctx));
8118
8119 /*
8120 * Fill in the maps array, used for resolving defaults.
8121 */
8122 i = 0;
8123 options = NULL;
8124 result = cfg_map_get(config, "options", &options);
8125 if (result == ISC_R_SUCCESS) {
8126 maps[i++] = options;
8127 }
8128 maps[i++] = named_g_defaults;
8129 maps[i] = NULL;
8130
8131 /*
8132 * If bind.keys exists, load it. If "dnssec-validation auto"
8133 * is turned on, the root key found there will be used as a
8134 * default trust anchor.
8135 */
8136 obj = NULL;
8137 result = named_config_get(maps, "bindkeys-file", &obj);
8138 INSIST(result == ISC_R_SUCCESS);
8139 CHECKM(setstring(server, &server->bindkeysfile,
8140 cfg_obj_asstring(obj)), "strdup");
8141
8142 if (access(server->bindkeysfile, R_OK) == 0) {
8143 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8144 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8145 "reading built-in trust anchors "
8146 "from file '%s'", server->bindkeysfile);
8147
8148 CHECK(cfg_parser_create(named_g_mctx, named_g_lctx,
8149 &bindkeys_parser));
8150
8151 result = cfg_parse_file(bindkeys_parser, server->bindkeysfile,
8152 &cfg_type_bindkeys, &bindkeys);
8153 CHECK(result);
8154 } else {
8155 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8156 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8157 "unable to open '%s'; using built-in keys "
8158 "instead", server->bindkeysfile);
8159 }
8160
8161 /* Ensure exclusive access to configuration data. */
8162 if (!exclusive) {
8163 result = isc_task_beginexclusive(server->task);
8164 RUNTIME_CHECK(result == ISC_R_SUCCESS);
8165 exclusive = true;
8166 }
8167
8168 /*
8169 * Set process limits, which (usually) needs to be done as root.
8170 */
8171 set_limits(maps);
8172
8173 /*
8174 * Check the process lockfile.
8175 */
8176 CHECK(check_lockfile(server, config, first_time));
8177
8178 /*
8179 * Check if max number of open sockets that the system allows is
8180 * sufficiently large. Failing this condition is not necessarily fatal,
8181 * but may cause subsequent runtime failures for a busy recursive
8182 * server.
8183 */
8184 result = isc_socketmgr_getmaxsockets(named_g_socketmgr, &maxsocks);
8185 if (result != ISC_R_SUCCESS) {
8186 maxsocks = 0;
8187 }
8188 result = isc_resource_getcurlimit(isc_resource_openfiles, &nfiles);
8189 if (result == ISC_R_SUCCESS && (isc_resourcevalue_t)maxsocks > nfiles) {
8190 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8191 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8192 "max open files (%" PRIu64 ")"
8193 " is smaller than max sockets (%u)",
8194 nfiles, maxsocks);
8195 }
8196
8197 /*
8198 * Set the number of socket reserved for TCP, stdio etc.
8199 */
8200 obj = NULL;
8201 result = named_config_get(maps, "reserved-sockets", &obj);
8202 INSIST(result == ISC_R_SUCCESS);
8203 reserved = cfg_obj_asuint32(obj);
8204 if (maxsocks != 0) {
8205 if (maxsocks < 128U) { /* Prevent underflow. */
8206 reserved = 0;
8207 } else if (reserved > maxsocks - 128U) { /* Minimum UDP space. */
8208 reserved = maxsocks - 128;
8209 }
8210 }
8211 /* Minimum TCP/stdio space. */
8212 if (reserved < 128U) {
8213 reserved = 128;
8214 }
8215 if (reserved + 128U > maxsocks && maxsocks != 0) {
8216 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8217 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
8218 "less than 128 UDP sockets available after "
8219 "applying 'reserved-sockets' and 'maxsockets'");
8220 }
8221 isc_socketmgr_setreserved(named_g_socketmgr, reserved);
8222
8223#ifdef HAVE_GEOIP
8224 /*
8225 * Initialize GeoIP databases from the configured location.
8226 * This should happen before configuring any ACLs, so that we
8227 * know what databases are available and can reject any GeoIP
8228 * ACLs that can't work.
8229 */
8230 obj = NULL;
8231 result = named_config_get(maps, "geoip-directory", &obj);
8232 if (result == ISC_R_SUCCESS && cfg_obj_isstring(obj)) {
8233 char *dir;
8234 DE_CONST(cfg_obj_asstring(obj), dir);
8235 named_geoip_load(dir);
8236 } else {
8237 named_geoip_load(NULL);
8238 }
8239 named_g_aclconfctx->geoip = named_g_geoip;
8240#endif /* HAVE_GEOIP */
8241
8242 /*
8243 * Configure various server options.
8244 */
8245 configure_server_quota(maps, "transfers-out",
8246 &server->sctx->xfroutquota);
8247 configure_server_quota(maps, "tcp-clients", &server->sctx->tcpquota);
8248 configure_server_quota(maps, "recursive-clients",
8249 &server->sctx->recursionquota);
8250
8251 max = isc_quota_getmax(&server->sctx->recursionquota);
8252 if (max > 1000) {
8253 unsigned margin = ISC_MAX(100, named_g_cpus + 1);
8254 if (margin + 100 > max) {
8255 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8256 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8257 "'recursive-clients %d' too low when "
8258 "running with %d worker threads",
8259 max, named_g_cpus);
8260 CHECK(ISC_R_RANGE);
8261 }
8262 softquota = max - margin;
8263 } else {
8264 softquota = (max * 90) / 100;
8265 }
8266
8267 isc_quota_soft(&server->sctx->recursionquota, softquota);
8268
8269 /*
8270 * Set "blackhole". Only legal at options level; there is
8271 * no default.
8272 */
8273 CHECK(configure_view_acl(NULL, config, NULL, "blackhole", NULL,
8274 named_g_aclconfctx, named_g_mctx,
8275 &server->sctx->blackholeacl));
8276 if (server->sctx->blackholeacl != NULL) {
8277 dns_dispatchmgr_setblackhole(named_g_dispatchmgr,
8278 server->sctx->blackholeacl);
8279 }
8280
8281 /*
8282 * Set "keep-response-order". Only legal at options or
8283 * global defaults level.
8284 */
8285 CHECK(configure_view_acl(NULL, config, named_g_config,
8286 "keep-response-order", NULL,
8287 named_g_aclconfctx, named_g_mctx,
8288 &server->sctx->keepresporder));
8289
8290 obj = NULL;
8291 result = named_config_get(maps, "match-mapped-addresses", &obj);
8292 INSIST(result == ISC_R_SUCCESS);
8293 env->match_mapped = cfg_obj_asboolean(obj);
8294
8295 CHECKM(named_statschannels_configure(named_g_server, config,
8296 named_g_aclconfctx),
8297 "configuring statistics server(s)");
8298
8299 obj = NULL;
8300 result = named_config_get(maps, "tcp-initial-timeout", &obj);
8301 INSIST(result == ISC_R_SUCCESS);
8302 initial = cfg_obj_asuint32(obj);
8303 if (initial > 1200) {
8304 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8305 "tcp-initial-timeout value is out of range: "
8306 "lowering to 1200");
8307 initial = 1200;
8308 } else if (initial < 25) {
8309 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8310 "tcp-initial-timeout value is out of range: "
8311 "raising to 25");
8312 initial = 25;
8313 }
8314
8315 obj = NULL;
8316 result = named_config_get(maps, "tcp-idle-timeout", &obj);
8317 INSIST(result == ISC_R_SUCCESS);
8318 idle = cfg_obj_asuint32(obj);
8319 if (idle > 1200) {
8320 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8321 "tcp-idle-timeout value is out of range: "
8322 "lowering to 1200");
8323 idle = 1200;
8324 } else if (idle < 1) {
8325 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8326 "tcp-idle-timeout value is out of range: "
8327 "raising to 1");
8328 idle = 1;
8329 }
8330
8331 obj = NULL;
8332 result = named_config_get(maps, "tcp-keepalive-timeout", &obj);
8333 INSIST(result == ISC_R_SUCCESS);
8334 keepalive = cfg_obj_asuint32(obj);
8335 if (keepalive > MAX_TCP_TIMEOUT) {
8336 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8337 "tcp-keepalive-timeout value is out of range: "
8338 "lowering to %u", MAX_TCP_TIMEOUT);
8339 keepalive = MAX_TCP_TIMEOUT;
8340 } else if (keepalive < 1) {
8341 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8342 "tcp-keepalive-timeout value is out of range: "
8343 "raising to 1");
8344 keepalive = 1;
8345 }
8346
8347 obj = NULL;
8348 result = named_config_get(maps, "tcp-advertised-timeout", &obj);
8349 INSIST(result == ISC_R_SUCCESS);
8350 advertised = cfg_obj_asuint32(obj);
8351 if (advertised > MAX_TCP_TIMEOUT) {
8352 cfg_obj_log(obj, named_g_lctx, ISC_LOG_WARNING,
8353 "tcp-advertized-timeout value is out of range: "
8354 "lowering to %u", MAX_TCP_TIMEOUT);
8355 advertised = MAX_TCP_TIMEOUT;
8356 }
8357
8358 ns_server_settimeouts(named_g_server->sctx,
8359 initial, idle, keepalive, advertised);
8360
8361 /*
8362 * Configure sets of UDP query source ports.
8363 */
8364 CHECKM(isc_portset_create(named_g_mctx, &v4portset),
8365 "creating UDP port set");
8366 CHECKM(isc_portset_create(named_g_mctx, &v6portset),
8367 "creating UDP port set");
8368
8369 usev4ports = NULL;
8370 usev6ports = NULL;
8371 avoidv4ports = NULL;
8372 avoidv6ports = NULL;
8373
8374 (void)named_config_get(maps, "use-v4-udp-ports", &usev4ports);
8375 if (usev4ports != NULL) {
8376 portset_fromconf(v4portset, usev4ports, true);
8377 } else {
8378 CHECKM(isc_net_getudpportrange(AF_INET, &udpport_low,
8379 &udpport_high),
8380 "get the default UDP/IPv4 port range");
8381 if (udpport_low == udpport_high) {
8382 isc_portset_add(v4portset, udpport_low);
8383 } else {
8384 isc_portset_addrange(v4portset, udpport_low,
8385 udpport_high);
8386 }
8387 if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE4)) {
8388 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8389 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8390 "using default UDP/IPv4 port range: "
8391 "[%d, %d]", udpport_low, udpport_high);
8392 }
8393 }
8394 (void)named_config_get(maps, "avoid-v4-udp-ports", &avoidv4ports);
8395 if (avoidv4ports != NULL) {
8396 portset_fromconf(v4portset, avoidv4ports, false);
8397 }
8398
8399 (void)named_config_get(maps, "use-v6-udp-ports", &usev6ports);
8400 if (usev6ports != NULL) {
8401 portset_fromconf(v6portset, usev6ports, true);
8402 } else {
8403 CHECKM(isc_net_getudpportrange(AF_INET6, &udpport_low,
8404 &udpport_high),
8405 "get the default UDP/IPv6 port range");
8406 if (udpport_low == udpport_high) {
8407 isc_portset_add(v6portset, udpport_low);
8408 } else {
8409 isc_portset_addrange(v6portset, udpport_low,
8410 udpport_high);
8411 }
8412 if (!ns_server_getoption(server->sctx, NS_SERVER_DISABLE6)) {
8413 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8414 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8415 "using default UDP/IPv6 port range: "
8416 "[%d, %d]", udpport_low, udpport_high);
8417 }
8418 }
8419 (void)named_config_get(maps, "avoid-v6-udp-ports", &avoidv6ports);
8420 if (avoidv6ports != NULL) {
8421 portset_fromconf(v6portset, avoidv6ports, false);
8422 }
8423
8424 dns_dispatchmgr_setavailports(named_g_dispatchmgr, v4portset,
8425 v6portset);
8426
8427 /*
8428 * Set the EDNS UDP size when we don't match a view.
8429 */
8430 obj = NULL;
8431 result = named_config_get(maps, "edns-udp-size", &obj);
8432 INSIST(result == ISC_R_SUCCESS);
8433 udpsize = cfg_obj_asuint32(obj);
8434 if (udpsize < 512) {
8435 udpsize = 512;
8436 }
8437 if (udpsize > 4096) {
8438 udpsize = 4096;
8439 }
8440 server->sctx->udpsize = (uint16_t)udpsize;
8441
8442 /* Set the transfer message size for TCP */
8443 obj = NULL;
8444 result = named_config_get(maps, "transfer-message-size", &obj);
8445 INSIST(result == ISC_R_SUCCESS);
8446 transfer_message_size = cfg_obj_asuint32(obj);
8447 if (transfer_message_size < 512) {
8448 transfer_message_size = 512;
8449 } else if (transfer_message_size > 65535) {
8450 transfer_message_size = 65535;
8451 }
8452 server->sctx->transfer_tcp_message_size =
8453 (uint16_t) transfer_message_size;
8454
8455 /*
8456 * Configure the zone manager.
8457 */
8458 obj = NULL;
8459 result = named_config_get(maps, "transfers-in", &obj);
8460 INSIST(result == ISC_R_SUCCESS);
8461 dns_zonemgr_settransfersin(server->zonemgr, cfg_obj_asuint32(obj));
8462
8463 obj = NULL;
8464 result = named_config_get(maps, "transfers-per-ns", &obj);
8465 INSIST(result == ISC_R_SUCCESS);
8466 dns_zonemgr_settransfersperns(server->zonemgr, cfg_obj_asuint32(obj));
8467
8468 obj = NULL;
8469 result = named_config_get(maps, "notify-rate", &obj);
8470 INSIST(result == ISC_R_SUCCESS);
8471 dns_zonemgr_setnotifyrate(server->zonemgr, cfg_obj_asuint32(obj));
8472
8473 obj = NULL;
8474 result = named_config_get(maps, "startup-notify-rate", &obj);
8475 INSIST(result == ISC_R_SUCCESS);
8476 dns_zonemgr_setstartupnotifyrate(server->zonemgr,
8477 cfg_obj_asuint32(obj));
8478
8479 obj = NULL;
8480 result = named_config_get(maps, "serial-query-rate", &obj);
8481 INSIST(result == ISC_R_SUCCESS);
8482 dns_zonemgr_setserialqueryrate(server->zonemgr, cfg_obj_asuint32(obj));
8483
8484 /*
8485 * Determine which port to use for listening for incoming connections.
8486 */
8487 if (named_g_port != 0) {
8488 listen_port = named_g_port;
8489 } else {
8490 CHECKM(named_config_getport(config, &listen_port), "port");
8491 }
8492
8493 /*
8494 * Determing the default DSCP code point.
8495 */
8496 CHECKM(named_config_getdscp(config, &named_g_dscp), "dscp");
8497
8498 /*
8499 * Find the listen queue depth.
8500 */
8501 obj = NULL;
8502 result = named_config_get(maps, "tcp-listen-queue", &obj);
8503 INSIST(result == ISC_R_SUCCESS);
8504 backlog = cfg_obj_asuint32(obj);
8505 if ((backlog > 0) && (backlog < 10)) {
8506 backlog = 10;
8507 }
8508 ns_interfacemgr_setbacklog(server->interfacemgr, backlog);
8509
8510 /*
8511 * Configure the interface manager according to the "listen-on"
8512 * statement.
8513 */
8514 {
8515 const cfg_obj_t *clistenon = NULL;
8516 ns_listenlist_t *listenon = NULL;
8517
8518 clistenon = NULL;
8519 /*
8520 * Even though listen-on is present in the default
8521 * configuration, this way is easier.
8522 */
8523 if (options != NULL) {
8524 (void)cfg_map_get(options, "listen-on", &clistenon);
8525 }
8526 if (clistenon != NULL) {
8527 /* check return code? */
8528 (void)ns_listenlist_fromconfig(clistenon, config,
8529 named_g_aclconfctx,
8530 named_g_mctx, AF_INET,
8531 &listenon);
8532 } else {
8533 /*
8534 * Not specified, use default.
8535 */
8536 CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8537 -1, true, &listenon));
8538 }
8539 if (listenon != NULL) {
8540 ns_interfacemgr_setlistenon4(server->interfacemgr,
8541 listenon);
8542 ns_listenlist_detach(&listenon);
8543 }
8544 }
8545 /*
8546 * Ditto for IPv6.
8547 */
8548 {
8549 const cfg_obj_t *clistenon = NULL;
8550 ns_listenlist_t *listenon = NULL;
8551
8552 if (options != NULL) {
8553 (void)cfg_map_get(options, "listen-on-v6", &clistenon);
8554 }
8555 if (clistenon != NULL) {
8556 /* check return code? */
8557 (void)ns_listenlist_fromconfig(clistenon, config,
8558 named_g_aclconfctx,
8559 named_g_mctx, AF_INET6,
8560 &listenon);
8561 } else {
8562 /*
8563 * Not specified, use default.
8564 */
8565 CHECK(ns_listenlist_default(named_g_mctx, listen_port,
8566 -1, true, &listenon));
8567 }
8568 if (listenon != NULL) {
8569 ns_interfacemgr_setlistenon6(server->interfacemgr,
8570 listenon);
8571 ns_listenlist_detach(&listenon);
8572 }
8573 }
8574
8575 /*
8576 * Rescan the interface list to pick up changes in the
8577 * listen-on option. It's important that we do this before we try
8578 * to configure the query source, since the dispatcher we use might
8579 * be shared with an interface.
8580 */
8581 result = ns_interfacemgr_scan(server->interfacemgr, true);
8582
8583 /*
8584 * Check that named is able to TCP listen on at least one
8585 * interface. Otherwise, another named process could be running
8586 * and we should fail.
8587 */
8588 if (first_time && (result == ISC_R_ADDRINUSE)) {
8589 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8590 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8591 "unable to listen on any configured interfaces");
8592 result = ISC_R_FAILURE;
8593 goto cleanup;
8594 }
8595
8596 /*
8597 * Arrange for further interface scanning to occur periodically
8598 * as specified by the "interface-interval" option.
8599 */
8600 obj = NULL;
8601 result = named_config_get(maps, "interface-interval", &obj);
8602 INSIST(result == ISC_R_SUCCESS);
8603 interface_interval = cfg_obj_asuint32(obj) * 60;
8604 if (interface_interval == 0) {
8605 CHECK(isc_timer_reset(server->interface_timer,
8606 isc_timertype_inactive,
8607 NULL, NULL, true));
8608 } else if (server->interface_interval != interface_interval) {
8609 isc_interval_set(&interval, interface_interval, 0);
8610 CHECK(isc_timer_reset(server->interface_timer,
8611 isc_timertype_ticker,
8612 NULL, &interval, false));
8613 }
8614 server->interface_interval = interface_interval;
8615
8616 /*
8617 * Enable automatic interface scans.
8618 */
8619 obj = NULL;
8620 result = named_config_get(maps, "automatic-interface-scan", &obj);
8621 INSIST(result == ISC_R_SUCCESS);
8622 server->sctx->interface_auto = cfg_obj_asboolean(obj);
8623
8624 /*
8625 * Configure the dialup heartbeat timer.
8626 */
8627 obj = NULL;
8628 result = named_config_get(maps, "heartbeat-interval", &obj);
8629 INSIST(result == ISC_R_SUCCESS);
8630 heartbeat_interval = cfg_obj_asuint32(obj) * 60;
8631 if (heartbeat_interval == 0) {
8632 CHECK(isc_timer_reset(server->heartbeat_timer,
8633 isc_timertype_inactive,
8634 NULL, NULL, true));
8635 } else if (server->heartbeat_interval != heartbeat_interval) {
8636 isc_interval_set(&interval, heartbeat_interval, 0);
8637 CHECK(isc_timer_reset(server->heartbeat_timer,
8638 isc_timertype_ticker,
8639 NULL, &interval, false));
8640 }
8641 server->heartbeat_interval = heartbeat_interval;
8642
8643 isc_interval_set(&interval, 1200, 0);
8644 CHECK(isc_timer_reset(server->pps_timer, isc_timertype_ticker, NULL,
8645 &interval, false));
8646
8647 isc_interval_set(&interval, named_g_tat_interval, 0);
8648 CHECK(isc_timer_reset(server->tat_timer, isc_timertype_ticker, NULL,
8649 &interval, false));
8650
8651 /*
8652 * Write the PID file.
8653 */
8654 obj = NULL;
8655 if (named_config_get(maps, "pid-file", &obj) == ISC_R_SUCCESS) {
8656 if (cfg_obj_isvoid(obj)) {
8657 named_os_writepidfile(NULL, first_time);
8658 } else {
8659 named_os_writepidfile(cfg_obj_asstring(obj),
8660 first_time);
8661 }
8662 } else {
8663 named_os_writepidfile(named_g_defaultpidfile, first_time);
8664 }
8665
8666 /*
8667 * Configure the server-wide session key. This must be done before
8668 * configure views because zone configuration may need to know
8669 * session-keyname.
8670 *
8671 * Failure of session key generation isn't fatal at this time; if it
8672 * turns out that a session key is really needed but doesn't exist,
8673 * we'll treat it as a fatal error then.
8674 */
8675 (void)configure_session_key(maps, server, named_g_mctx);
8676
8677 views = NULL;
8678 (void)cfg_map_get(config, "view", &views);
8679
8680 /*
8681 * Create the views and count all the configured zones in
8682 * order to correctly size the zone manager's task table.
8683 * (We only count zones for configured views; the built-in
8684 * "bind" view can be ignored as it only adds a negligible
8685 * number of zones.)
8686 *
8687 * If we're allowing new zones, we need to be able to find the
8688 * new zone file and count those as well. So we setup the new
8689 * zone configuration context, but otherwise view configuration
8690 * waits until after the zone manager's task list has been sized.
8691 */
8692 for (element = cfg_list_first(views);
8693 element != NULL;
8694 element = cfg_list_next(element))
8695 {
8696 cfg_obj_t *vconfig = cfg_listelt_value(element);
8697 const cfg_obj_t *voptions = cfg_tuple_get(vconfig, "options");
8698 int nzf_num_zones;
8699
8700 view = NULL;
8701
8702 CHECK(create_view(vconfig, &viewlist, &view));
8703 INSIST(view != NULL);
8704
8705 num_zones += count_zones(voptions);
8706
8707 CHECK(setup_newzones(view, config, vconfig, conf_parser,
8708 named_g_aclconfctx, &nzf_num_zones));
8709 num_zones += nzf_num_zones;
8710
8711 dns_view_detach(&view);
8712 }
8713
8714 /*
8715 * If there were no explicit views then we do the default
8716 * view here.
8717 */
8718 if (views == NULL) {
8719 int nzf_num_zones;
8720
8721 CHECK(create_view(NULL, &viewlist, &view));
8722 INSIST(view != NULL);
8723
8724 num_zones = count_zones(config);
8725
8726 CHECK(setup_newzones(view, config, NULL, conf_parser,
8727 named_g_aclconfctx, &nzf_num_zones));
8728 num_zones += nzf_num_zones;
8729
8730 dns_view_detach(&view);
8731 }
8732
8733 /*
8734 * Zones have been counted; set the zone manager task pool size.
8735 */
8736 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8737 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8738 "sizing zone task pool based on %d zones", num_zones);
8739 CHECK(dns_zonemgr_setsize(named_g_server->zonemgr, num_zones));
8740
8741 /*
8742 * Configure and freeze all explicit views. Explicit
8743 * views that have zones were already created at parsing
8744 * time, but views with no zones must be created here.
8745 */
8746 for (element = cfg_list_first(views);
8747 element != NULL;
8748 element = cfg_list_next(element))
8749 {
8750 cfg_obj_t *vconfig = cfg_listelt_value(element);
8751
8752 view = NULL;
8753 CHECK(find_view(vconfig, &viewlist, &view));
8754 CHECK(configure_view(view, &viewlist, config, vconfig,
8755 &cachelist, bindkeys, named_g_mctx,
8756 named_g_aclconfctx, true));
8757 dns_view_freeze(view);
8758 dns_view_detach(&view);
8759 }
8760
8761 /*
8762 * Make sure we have a default view if and only if there
8763 * were no explicit views.
8764 */
8765 if (views == NULL) {
8766 view = NULL;
8767 CHECK(find_view(NULL, &viewlist, &view));
8768 CHECK(configure_view(view, &viewlist, config, NULL,
8769 &cachelist, bindkeys,
8770 named_g_mctx, named_g_aclconfctx,
8771 true));
8772 dns_view_freeze(view);
8773 dns_view_detach(&view);
8774 }
8775
8776 /*
8777 * Create (or recreate) the built-in views.
8778 */
8779 builtin_views = NULL;
8780 RUNTIME_CHECK(cfg_map_get(named_g_config, "view",
8781 &builtin_views) == ISC_R_SUCCESS);
8782 for (element = cfg_list_first(builtin_views);
8783 element != NULL;
8784 element = cfg_list_next(element))
8785 {
8786 cfg_obj_t *vconfig = cfg_listelt_value(element);
8787
8788 CHECK(create_view(vconfig, &builtin_viewlist, &view));
8789 CHECK(configure_view(view, &viewlist, config, vconfig,
8790 &cachelist, bindkeys,
8791 named_g_mctx, named_g_aclconfctx,
8792 false));
8793 dns_view_freeze(view);
8794 dns_view_detach(&view);
8795 view = NULL;
8796 }
8797
8798 /* Now combine the two viewlists into one */
8799 ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
8800
8801 /*
8802 * Commit any dns_zone_setview() calls on all zones in the new
8803 * view.
8804 */
8805 for (view = ISC_LIST_HEAD(viewlist);
8806 view != NULL;
8807 view = ISC_LIST_NEXT(view, link))
8808 {
8809 dns_view_setviewcommit(view);
8810 }
8811
8812 /* Swap our new view list with the production one. */
8813 tmpviewlist = server->viewlist;
8814 server->viewlist = viewlist;
8815 viewlist = tmpviewlist;
8816
8817 /* Make the view list available to each of the views */
8818 view = ISC_LIST_HEAD(server->viewlist);
8819 while (view != NULL) {
8820 view->viewlist = &server->viewlist;
8821 view = ISC_LIST_NEXT(view, link);
8822 }
8823
8824 /* Swap our new cache list with the production one. */
8825 tmpcachelist = server->cachelist;
8826 server->cachelist = cachelist;
8827 cachelist = tmpcachelist;
8828
8829 /* Load the TKEY information from the configuration. */
8830 if (options != NULL) {
8831 dns_tkeyctx_t *t = NULL;
8832 CHECKM(named_tkeyctx_fromconfig(options, named_g_mctx, &t),
8833 "configuring TKEY");
8834 if (server->sctx->tkeyctx != NULL) {
8835 dns_tkeyctx_destroy(&server->sctx->tkeyctx);
8836 }
8837 server->sctx->tkeyctx = t;
8838 }
8839
8840 /*
8841 * Bind the control port(s).
8842 */
8843 CHECKM(named_controls_configure(named_g_server->controls, config,
8844 named_g_aclconfctx),
8845 "binding control channel(s)");
8846
8847#ifdef HAVE_LMDB
8848 /*
8849 * If we're using LMDB, we may have created newzones databases
8850 * as root, making it impossible to reopen them later after
8851 * switching to a new userid. We close them now, and reopen
8852 * after relinquishing privileges them.
8853 */
8854 if (first_time) {
8855 for (view = ISC_LIST_HEAD(server->viewlist);
8856 view != NULL;
8857 view = ISC_LIST_NEXT(view, link))
8858 {
8859 nzd_env_close(view);
8860 }
8861 }
8862#endif /* HAVE_LMDB */
8863
8864 /*
8865 * Relinquish root privileges.
8866 */
8867 if (first_time) {
8868 named_os_changeuser();
8869 }
8870
8871#if 0
8872 /*
8873 * Check that the working directory is writable.
8874 */
8875 if (!isc_file_isdirwritable(".")) {
8876 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8877 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
8878 "the working directory is not writable");
8879 result = ISC_R_NOPERM;
8880 goto cleanup;
8881 }
8882#endif
8883#ifdef HAVE_LMDB
8884 /*
8885 * Reopen NZD databases.
8886 */
8887 if (first_time) {
8888 for (view = ISC_LIST_HEAD(server->viewlist);
8889 view != NULL;
8890 view = ISC_LIST_NEXT(view, link))
8891 {
8892 nzd_env_reopen(view);
8893 }
8894 }
8895#endif /* HAVE_LMDB */
8896
8897 /*
8898 * Configure the logging system.
8899 *
8900 * Do this after changing UID to make sure that any log
8901 * files specified in named.conf get created by the
8902 * unprivileged user, not root.
8903 */
8904 if (named_g_logstderr) {
8905 const cfg_obj_t *logobj = NULL;
8906
8907 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8908 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
8909 "not using config file logging "
8910 "statement for logging due to "
8911 "-g option");
8912
8913 (void)cfg_map_get(config, "logging", &logobj);
8914 if (logobj != NULL) {
8915 result = named_logconfig(NULL, logobj);
8916 if (result != ISC_R_SUCCESS) {
8917 isc_log_write(named_g_lctx,
8918 NAMED_LOGCATEGORY_GENERAL,
8919 NAMED_LOGMODULE_SERVER,
8920 ISC_LOG_ERROR,
8921 "checking logging configuration "
8922 "failed: %s",
8923 isc_result_totext(result));
8924 goto cleanup;
8925 }
8926 }
8927 } else {
8928 const cfg_obj_t *logobj = NULL;
8929
8930 CHECKM(isc_logconfig_create(named_g_lctx, &logc),
8931 "creating new logging configuration");
8932
8933 logobj = NULL;
8934 (void)cfg_map_get(config, "logging", &logobj);
8935 if (logobj != NULL) {
8936 CHECKM(named_logconfig(logc, logobj),
8937 "configuring logging");
8938 } else {
8939 CHECKM(named_log_setdefaultchannels(logc),
8940 "setting up default logging channels");
8941 CHECKM(named_log_setunmatchedcategory(logc),
8942 "setting up default 'category unmatched'");
8943 CHECKM(named_log_setdefaultcategory(logc),
8944 "setting up default 'category default'");
8945 }
8946
8947 CHECKM(isc_logconfig_use(named_g_lctx, logc),
8948 "installing logging configuration");
8949 logc = NULL;
8950
8951 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
8952 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
8953 "now using logging configuration from "
8954 "config file");
8955 }
8956
8957 /*
8958 * Set the default value of the query logging flag depending
8959 * whether a "queries" category has been defined. This is
8960 * a disgusting hack, but we need to do this for BIND 8
8961 * compatibility.
8962 */
8963 if (first_time) {
8964 const cfg_obj_t *logobj = NULL;
8965 const cfg_obj_t *categories = NULL;
8966
8967 obj = NULL;
8968 if (named_config_get(maps, "querylog", &obj) == ISC_R_SUCCESS) {
8969 ns_server_setoption(server->sctx,
8970 NS_SERVER_LOGQUERIES,
8971 cfg_obj_asboolean(obj));
8972 } else {
8973
8974 (void)cfg_map_get(config, "logging", &logobj);
8975 if (logobj != NULL)
8976 (void)cfg_map_get(logobj, "category",
8977 &categories);
8978 if (categories != NULL) {
8979 for (element = cfg_list_first(categories);
8980 element != NULL;
8981 element = cfg_list_next(element))
8982 {
8983 const cfg_obj_t *catobj;
8984 const char *str;
8985
8986 obj = cfg_listelt_value(element);
8987 catobj = cfg_tuple_get(obj, "name");
8988 str = cfg_obj_asstring(catobj);
8989 if (strcasecmp(str, "queries") == 0)
8990 ns_server_setoption(
8991 server->sctx,
8992 NS_SERVER_LOGQUERIES,
8993 true);
8994 }
8995 }
8996 }
8997 }
8998
8999 obj = NULL;
9000 if (options != NULL &&
9001 cfg_map_get(options, "memstatistics", &obj) == ISC_R_SUCCESS)
9002 {
9003 named_g_memstatistics = cfg_obj_asboolean(obj);
9004 } else {
9005 named_g_memstatistics =
9006 ((isc_mem_debugging & ISC_MEM_DEBUGRECORD) != 0);
9007 }
9008
9009 obj = NULL;
9010 if (named_config_get(maps, "memstatistics-file", &obj) == ISC_R_SUCCESS)
9011 {
9012 named_main_setmemstats(cfg_obj_asstring(obj));
9013 } else if (named_g_memstatistics) {
9014 named_main_setmemstats("named.memstats");
9015 } else {
9016 named_main_setmemstats(NULL);
9017 }
9018
9019 obj = NULL;
9020 result = named_config_get(maps, "statistics-file", &obj);
9021 INSIST(result == ISC_R_SUCCESS);
9022 CHECKM(setstring(server, &server->statsfile, cfg_obj_asstring(obj)),
9023 "strdup");
9024
9025 obj = NULL;
9026 result = named_config_get(maps, "dump-file", &obj);
9027 INSIST(result == ISC_R_SUCCESS);
9028 CHECKM(setstring(server, &server->dumpfile, cfg_obj_asstring(obj)),
9029 "strdup");
9030
9031 obj = NULL;
9032 result = named_config_get(maps, "secroots-file", &obj);
9033 INSIST(result == ISC_R_SUCCESS);
9034 CHECKM(setstring(server, &server->secrootsfile, cfg_obj_asstring(obj)),
9035 "strdup");
9036
9037 obj = NULL;
9038 result = named_config_get(maps, "recursing-file", &obj);
9039 INSIST(result == ISC_R_SUCCESS);
9040 CHECKM(setstring(server, &server->recfile, cfg_obj_asstring(obj)),
9041 "strdup");
9042
9043 obj = NULL;
9044 result = named_config_get(maps, "version", &obj);
9045 if (result == ISC_R_SUCCESS) {
9046 CHECKM(setoptstring(server, &server->version, obj), "strdup");
9047 server->version_set = true;
9048 } else {
9049 server->version_set = false;
9050 }
9051
9052 obj = NULL;
9053 result = named_config_get(maps, "hostname", &obj);
9054 if (result == ISC_R_SUCCESS) {
9055 CHECKM(setoptstring(server, &server->hostname, obj), "strdup");
9056 server->hostname_set = true;
9057 } else {
9058 server->hostname_set = false;
9059 }
9060
9061 obj = NULL;
9062 result = named_config_get(maps, "server-id", &obj);
9063 server->sctx->gethostname = NULL;
9064 if (result == ISC_R_SUCCESS && cfg_obj_isboolean(obj)) {
9065 /* The parser translates "hostname" to true */
9066 server->sctx->gethostname = named_os_gethostname;
9067 result = ns_server_setserverid(server->sctx, NULL);
9068 } else if (result == ISC_R_SUCCESS && !cfg_obj_isvoid(obj)) {
9069 /* Found a quoted string */
9070 result = ns_server_setserverid(server->sctx,
9071 cfg_obj_asstring(obj));
9072 } else {
9073 result = ns_server_setserverid(server->sctx, NULL);
9074 }
9075 RUNTIME_CHECK(result == ISC_R_SUCCESS);
9076
9077 obj = NULL;
9078 result = named_config_get(maps, "flush-zones-on-shutdown", &obj);
9079 if (result == ISC_R_SUCCESS) {
9080 server->flushonshutdown = cfg_obj_asboolean(obj);
9081 } else {
9082 server->flushonshutdown = false;
9083 }
9084
9085 obj = NULL;
9086 result = named_config_get(maps, "answer-cookie", &obj);
9087 INSIST(result == ISC_R_SUCCESS);
9088 server->sctx->answercookie = cfg_obj_asboolean(obj);
9089
9090 obj = NULL;
9091 result = named_config_get(maps, "cookie-algorithm", &obj);
9092 INSIST(result == ISC_R_SUCCESS);
9093 if (strcasecmp(cfg_obj_asstring(obj), "aes") == 0) {
9094 server->sctx->cookiealg = ns_cookiealg_aes;
9095 } else if (strcasecmp(cfg_obj_asstring(obj), "sha1") == 0) {
9096 server->sctx->cookiealg = ns_cookiealg_sha1;
9097 } else if (strcasecmp(cfg_obj_asstring(obj), "sha256") == 0) {
9098 server->sctx->cookiealg = ns_cookiealg_sha256;
9099 } else {
9100 INSIST(0);
9101 ISC_UNREACHABLE();
9102 }
9103
9104 obj = NULL;
9105 result = named_config_get(maps, "cookie-secret", &obj);
9106 if (result == ISC_R_SUCCESS) {
9107 const char *str;
9108 bool first = true;
9109 isc_buffer_t b;
9110 unsigned int usedlength;
9111 unsigned int expectedlength;
9112
9113 for (element = cfg_list_first(obj);
9114 element != NULL;
9115 element = cfg_list_next(element))
9116 {
9117 obj = cfg_listelt_value(element);
9118 str = cfg_obj_asstring(obj);
9119
9120 if (first) {
9121 memset(server->sctx->secret, 0,
9122 sizeof(server->sctx->secret));
9123 isc_buffer_init(&b, server->sctx->secret,
9124 sizeof(server->sctx->secret));
9125 result = isc_hex_decodestring(str, &b);
9126 if (result != ISC_R_SUCCESS &&
9127 result != ISC_R_NOSPACE)
9128 {
9129 goto cleanup;
9130 }
9131 first = false;
9132 } else {
9133 altsecret = isc_mem_get(server->sctx->mctx,
9134 sizeof(*altsecret));
9135 if (altsecret == NULL) {
9136 result = ISC_R_NOMEMORY;
9137 goto cleanup;
9138 }
9139 isc_buffer_init(&b, altsecret->secret,
9140 sizeof(altsecret->secret));
9141 result = isc_hex_decodestring(str, &b);
9142 if (result != ISC_R_SUCCESS &&
9143 result != ISC_R_NOSPACE)
9144 {
9145 isc_mem_put(server->sctx->mctx,
9146 altsecret,
9147 sizeof(*altsecret));
9148 goto cleanup;
9149 }
9150 ISC_LIST_INITANDAPPEND(altsecrets,
9151 altsecret, link);
9152 }
9153
9154 usedlength = isc_buffer_usedlength(&b);
9155 switch (server->sctx->cookiealg) {
9156 case ns_cookiealg_aes:
9157 expectedlength = ISC_AES128_KEYLENGTH;
9158 if (usedlength != expectedlength) {
9159 CHECKM(ISC_R_RANGE,
9160 "AES cookie-secret must be "
9161 "128 bits");
9162 }
9163 break;
9164 case ns_cookiealg_sha1:
9165 expectedlength =
9166 isc_md_type_get_size(ISC_MD_SHA1);
9167 if (usedlength != expectedlength) {
9168 CHECKM(ISC_R_RANGE,
9169 "SHA1 cookie-secret must be "
9170 "160 bits");
9171 }
9172 break;
9173 case ns_cookiealg_sha256:
9174 expectedlength =
9175 isc_md_type_get_size(ISC_MD_SHA256);
9176 if (usedlength != expectedlength) {
9177 CHECKM(ISC_R_RANGE,
9178 "SHA256 cookie-secret must be "
9179 "256 bits");
9180 }
9181 break;
9182 }
9183 }
9184 } else {
9185 isc_nonce_buf(server->sctx->secret,
9186 sizeof(server->sctx->secret));
9187 }
9188
9189 /*
9190 * Swap altsecrets lists.
9191 */
9192 tmpaltsecrets = server->sctx->altsecrets;
9193 server->sctx->altsecrets = altsecrets;
9194 altsecrets = tmpaltsecrets;
9195
9196 (void) named_server_loadnta(server);
9197
9198#ifdef USE_DNSRPS
9199 /*
9200 * Start and connect to the DNS Response Policy Service
9201 * daemon, dnsrpzd, for each view that uses DNSRPS.
9202 */
9203 for (view = ISC_LIST_HEAD(server->viewlist);
9204 view != NULL;
9205 view = ISC_LIST_NEXT(view, link)) {
9206 result = dns_dnsrps_connect(view->rpzs);
9207 if (result != ISC_R_SUCCESS) {
9208 view = NULL;
9209 goto cleanup;
9210 }
9211 }
9212#endif
9213
9214 result = ISC_R_SUCCESS;
9215
9216 cleanup:
9217 if (logc != NULL) {
9218 isc_logconfig_destroy(&logc);
9219 }
9220
9221 if (v4portset != NULL) {
9222 isc_portset_destroy(named_g_mctx, &v4portset);
9223 }
9224
9225 if (v6portset != NULL) {
9226 isc_portset_destroy(named_g_mctx, &v6portset);
9227 }
9228
9229 if (conf_parser != NULL) {
9230 if (config != NULL) {
9231 cfg_obj_destroy(conf_parser, &config);
9232 }
9233 cfg_parser_destroy(&conf_parser);
9234 }
9235
9236 if (bindkeys_parser != NULL) {
9237 if (bindkeys != NULL) {
9238 cfg_obj_destroy(bindkeys_parser, &bindkeys);
9239 }
9240 cfg_parser_destroy(&bindkeys_parser);
9241 }
9242
9243 if (view != NULL) {
9244 dns_view_detach(&view);
9245 }
9246
9247 ISC_LIST_APPENDLIST(viewlist, builtin_viewlist, link);
9248
9249 /*
9250 * This cleans up either the old production view list
9251 * or our temporary list depending on whether they
9252 * were swapped above or not.
9253 */
9254 for (view = ISC_LIST_HEAD(viewlist);
9255 view != NULL;
9256 view = view_next) {
9257 view_next = ISC_LIST_NEXT(view, link);
9258 ISC_LIST_UNLINK(viewlist, view, link);
9259 if (result == ISC_R_SUCCESS &&
9260 strcmp(view->name, "_bind") != 0)
9261 {
9262 dns_view_setviewrevert(view);
9263 (void)dns_zt_apply(view->zonetable, false,
9264 NULL, removed, view);
9265 }
9266 dns_view_detach(&view);
9267 }
9268
9269 /* Same cleanup for cache list. */
9270 while ((nsc = ISC_LIST_HEAD(cachelist)) != NULL) {
9271 ISC_LIST_UNLINK(cachelist, nsc, link);
9272 dns_cache_detach(&nsc->cache);
9273 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9274 }
9275
9276 /* Cleanup for altsecrets list. */
9277 while ((altsecret = ISC_LIST_HEAD(altsecrets)) != NULL) {
9278 ISC_LIST_UNLINK(altsecrets, altsecret, link);
9279 isc_mem_put(server->sctx->mctx, altsecret, sizeof(*altsecret));
9280 }
9281
9282 /*
9283 * Adjust the listening interfaces in accordance with the source
9284 * addresses specified in views and zones.
9285 */
9286 if (isc_net_probeipv6() == ISC_R_SUCCESS) {
9287 adjust_interfaces(server, named_g_mctx);
9288 }
9289
9290 /*
9291 * Record the time of most recent configuration
9292 */
9293 tresult = isc_time_now(&named_g_configtime);
9294 if (tresult != ISC_R_SUCCESS) {
9295 named_main_earlyfatal("isc_time_now() failed: %s",
9296 isc_result_totext(result));
9297 }
9298
9299 /* Relinquish exclusive access to configuration data. */
9300 if (exclusive) {
9301 isc_task_endexclusive(server->task);
9302 }
9303
9304 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9305 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
9306 "load_configuration: %s",
9307 isc_result_totext(result));
9308
9309 return (result);
9310}
9311
9312static isc_result_t
9313view_loaded(void *arg) {
9314 isc_result_t result;
9315 ns_zoneload_t *zl = (ns_zoneload_t *) arg;
9316 named_server_t *server = zl->server;
9317 bool reconfig = zl->reconfig;
9318
9319
9320 /*
9321 * Force zone maintenance. Do this after loading
9322 * so that we know when we need to force AXFR of
9323 * slave zones whose master files are missing.
9324 *
9325 * We use the zoneload reference counter to let us
9326 * know when all views are finished.
9327 */
9328 if (isc_refcount_decrement(&zl->refs) == 1) {
9329
9330 isc_refcount_destroy(&zl->refs);
9331 isc_mem_put(server->mctx, zl, sizeof (*zl));
9332
9333 /*
9334 * To maintain compatibility with log parsing tools that might
9335 * be looking for this string after "rndc reconfig", we keep it
9336 * as it is
9337 */
9338 if (reconfig) {
9339 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9340 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9341 "any newly configured zones are now loaded");
9342 } else {
9343 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9344 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9345 "all zones loaded");
9346 }
9347
9348 CHECKFATAL(dns_zonemgr_forcemaint(server->zonemgr),
9349 "forcing zone maintenance");
9350
9351 named_os_started();
9352
9353#ifdef HAVE_FIPS_MODE
9354 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9355 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9356 "FIPS mode is %s",
9357 FIPS_mode() ? "enabled" : "disabled");
9358#endif
9359 server->reload_in_progress = false;
9360
9361 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9362 NAMED_LOGMODULE_SERVER, ISC_LOG_NOTICE,
9363 "running");
9364 }
9365
9366 return (ISC_R_SUCCESS);
9367}
9368
9369static isc_result_t
9370load_zones(named_server_t *server, bool init, bool reconfig) {
9371 isc_result_t result;
9372 dns_view_t *view;
9373 ns_zoneload_t *zl;
9374
9375 zl = isc_mem_get(server->mctx, sizeof (*zl));
9376 if (zl == NULL)
9377 return (ISC_R_NOMEMORY);
9378 zl->server = server;
9379 zl->reconfig = reconfig;
9380
9381 result = isc_task_beginexclusive(server->task);
9382 RUNTIME_CHECK(result == ISC_R_SUCCESS);
9383
9384 isc_refcount_init(&zl->refs, 1);
9385
9386 /*
9387 * Schedule zones to be loaded from disk.
9388 */
9389 for (view = ISC_LIST_HEAD(server->viewlist);
9390 view != NULL;
9391 view = ISC_LIST_NEXT(view, link))
9392 {
9393 if (view->managed_keys != NULL) {
9394 result = dns_zone_load(view->managed_keys, false);
9395 if (result != ISC_R_SUCCESS &&
9396 result != DNS_R_UPTODATE &&
9397 result != DNS_R_CONTINUE)
9398 goto cleanup;
9399 }
9400 if (view->redirect != NULL) {
9401 result = dns_zone_load(view->redirect, false);
9402 if (result != ISC_R_SUCCESS &&
9403 result != DNS_R_UPTODATE &&
9404 result != DNS_R_CONTINUE)
9405 goto cleanup;
9406 }
9407
9408 /*
9409 * 'dns_view_asyncload' calls view_loaded if there are no
9410 * zones.
9411 */
9412 isc_refcount_increment(&zl->refs);
9413 result = dns_view_asyncload(view, reconfig, view_loaded, zl);
9414 if (result != ISC_R_SUCCESS) {
9415 (void)isc_refcount_decrement(&zl->refs);
9416 goto cleanup;
9417 }
9418 }
9419
9420 cleanup:
9421 if (isc_refcount_decrement(&zl->refs) == 1) {
9422 isc_refcount_destroy(&zl->refs);
9423 isc_mem_put(server->mctx, zl, sizeof (*zl));
9424 } else if (init) {
9425 /*
9426 * Place the task manager into privileged mode. This
9427 * ensures that after we leave task-exclusive mode, no
9428 * other tasks will be able to run except for the ones
9429 * that are loading zones. (This should only be done during
9430 * the initial server setup; it isn't necessary during
9431 * a reload.)
9432 */
9433 isc_taskmgr_setprivilegedmode(named_g_taskmgr);
9434 }
9435
9436 isc_task_endexclusive(server->task);
9437 return (result);
9438}
9439
9440static void
9441run_server(isc_task_t *task, isc_event_t *event) {
9442 isc_result_t result;
9443 named_server_t *server = (named_server_t *)event->ev_arg;
9444
9445 INSIST(task == server->task);
9446
9447 isc_event_free(&event);
9448
9449 CHECKFATAL(dns_dispatchmgr_create(named_g_mctx, &named_g_dispatchmgr),
9450 "creating dispatch manager");
9451
9452 dns_dispatchmgr_setstats(named_g_dispatchmgr, server->resolverstats);
9453
9454#ifdef HAVE_GEOIP
9455 CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
9456 named_g_taskmgr, named_g_timermgr,
9457 named_g_socketmgr,
9458 named_g_dispatchmgr,
9459 server->task, named_g_udpdisp,
9460 named_g_geoip,
9461 &server->interfacemgr),
9462 "creating interface manager");
9463#else
9464 CHECKFATAL(ns_interfacemgr_create(named_g_mctx, server->sctx,
9465 named_g_taskmgr, named_g_timermgr,
9466 named_g_socketmgr,
9467 named_g_dispatchmgr,
9468 server->task, named_g_udpdisp,
9469 NULL,
9470 &server->interfacemgr),
9471 "creating interface manager");
9472#endif
9473
9474 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9475 NULL, NULL, server->task,
9476 interface_timer_tick,
9477 server, &server->interface_timer),
9478 "creating interface timer");
9479
9480 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9481 NULL, NULL, server->task,
9482 heartbeat_timer_tick,
9483 server, &server->heartbeat_timer),
9484 "creating heartbeat timer");
9485
9486 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9487 NULL, NULL, server->task, tat_timer_tick,
9488 server, &server->tat_timer),
9489 "creating trust anchor telemetry timer");
9490
9491 CHECKFATAL(isc_timer_create(named_g_timermgr, isc_timertype_inactive,
9492 NULL, NULL, server->task, pps_timer_tick,
9493 server, &server->pps_timer),
9494 "creating pps timer");
9495
9496 CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
9497 &named_g_parser),
9498 "creating default configuration parser");
9499
9500 CHECKFATAL(cfg_parser_create(named_g_mctx, named_g_lctx,
9501 &named_g_addparser),
9502 "creating additional configuration parser");
9503
9504 CHECKFATAL(load_configuration(named_g_conffile, server, true),
9505 "loading configuration");
9506
9507 CHECKFATAL(load_zones(server, true, false), "loading zones");
9508#ifdef ENABLE_AFL
9509 named_g_run_done = true;
9510#endif
9511}
9512
9513void
9514named_server_flushonshutdown(named_server_t *server, bool flush) {
9515 REQUIRE(NAMED_SERVER_VALID(server));
9516
9517 server->flushonshutdown = flush;
9518}
9519
9520static void
9521shutdown_server(isc_task_t *task, isc_event_t *event) {
9522 isc_result_t result;
9523 dns_view_t *view, *view_next;
9524 named_server_t *server = (named_server_t *)event->ev_arg;
9525 bool flush = server->flushonshutdown;
9526 named_cache_t *nsc;
9527
9528 UNUSED(task);
9529 INSIST(task == server->task);
9530
9531 result = isc_task_beginexclusive(server->task);
9532 RUNTIME_CHECK(result == ISC_R_SUCCESS);
9533
9534 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9535 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9536 "shutting down%s",
9537 flush ? ": flushing changes" : "");
9538
9539 named_statschannels_shutdown(server);
9540 named_controls_shutdown(server->controls);
9541 end_reserved_dispatches(server, true);
9542 cleanup_session_key(server, server->mctx);
9543
9544 if (named_g_aclconfctx != NULL)
9545 cfg_aclconfctx_detach(&named_g_aclconfctx);
9546
9547 cfg_obj_destroy(named_g_parser, &named_g_config);
9548 cfg_parser_destroy(&named_g_parser);
9549 cfg_parser_destroy(&named_g_addparser);
9550
9551 (void) named_server_saventa(server);
9552
9553 for (view = ISC_LIST_HEAD(server->viewlist);
9554 view != NULL;
9555 view = view_next) {
9556 view_next = ISC_LIST_NEXT(view, link);
9557 ISC_LIST_UNLINK(server->viewlist, view, link);
9558 if (flush)
9559 dns_view_flushanddetach(&view);
9560 else
9561 dns_view_detach(&view);
9562 }
9563
9564 /*
9565 * Shut down all dyndb instances.
9566 */
9567 dns_dyndb_cleanup(true);
9568
9569 while ((nsc = ISC_LIST_HEAD(server->cachelist)) != NULL) {
9570 ISC_LIST_UNLINK(server->cachelist, nsc, link);
9571 dns_cache_detach(&nsc->cache);
9572 isc_mem_put(server->mctx, nsc, sizeof(*nsc));
9573 }
9574
9575 isc_timer_detach(&server->interface_timer);
9576 isc_timer_detach(&server->heartbeat_timer);
9577 isc_timer_detach(&server->pps_timer);
9578 isc_timer_detach(&server->tat_timer);
9579
9580 ns_interfacemgr_shutdown(server->interfacemgr);
9581 ns_interfacemgr_detach(&server->interfacemgr);
9582
9583 dns_dispatchmgr_destroy(&named_g_dispatchmgr);
9584
9585 dns_zonemgr_shutdown(server->zonemgr);
9586
9587 if (named_g_sessionkey != NULL) {
9588 dns_tsigkey_detach(&named_g_sessionkey);
9589 dns_name_free(&named_g_sessionkeyname, server->mctx);
9590 }
9591#ifdef HAVE_DNSTAP
9592 dns_dt_shutdown();
9593#endif
9594#ifdef HAVE_GEOIP
9595 dns_geoip_shutdown();
9596#endif
9597
9598 dns_db_detach(&server->in_roothints);
9599
9600 isc_task_endexclusive(server->task);
9601
9602 isc_task_detach(&server->task);
9603
9604 isc_event_free(&event);
9605}
9606
9607/*%
9608 * Find a view that matches the source and destination addresses of a query.
9609 */
9610static isc_result_t
9611get_matching_view(isc_netaddr_t *srcaddr, isc_netaddr_t *destaddr,
9612 dns_message_t *message, dns_aclenv_t *env,
9613 isc_result_t *sigresult, dns_view_t **viewp)
9614{
9615 dns_view_t *view;
9616
9617 REQUIRE(message != NULL);
9618 REQUIRE(sigresult != NULL);
9619 REQUIRE(viewp != NULL && *viewp == NULL);
9620
9621 for (view = ISC_LIST_HEAD(named_g_server->viewlist);
9622 view != NULL;
9623 view = ISC_LIST_NEXT(view, link))
9624 {
9625 if (message->rdclass == view->rdclass ||
9626 message->rdclass == dns_rdataclass_any)
9627 {
9628 dns_name_t *tsig = NULL;
9629
9630 *sigresult = dns_message_rechecksig(message, view);
9631 if (*sigresult == ISC_R_SUCCESS) {
9632 dns_tsigkey_t *tsigkey;
9633
9634 tsigkey = message->tsigkey;
9635 tsig = dns_tsigkey_identity(tsigkey);
9636 }
9637
9638 if (dns_acl_allowed(srcaddr, tsig,
9639 view->matchclients, env) &&
9640 dns_acl_allowed(destaddr, tsig,
9641 view->matchdestinations, env) &&
9642 !(view->matchrecursiveonly &&
9643 (message->flags & DNS_MESSAGEFLAG_RD) == 0))
9644 {
9645 dns_view_attach(view, viewp);
9646 return (ISC_R_SUCCESS);
9647 }
9648 }
9649 }
9650
9651 return (ISC_R_NOTFOUND);
9652}
9653
9654void
9655named_server_create(isc_mem_t *mctx, named_server_t **serverp) {
9656 isc_result_t result;
9657 named_server_t *server = isc_mem_get(mctx, sizeof(*server));
9658
9659 if (server == NULL)
9660 fatal("allocating server object", ISC_R_NOMEMORY);
9661
9662 server->mctx = mctx;
9663 server->task = NULL;
9664 server->zonemgr = NULL;
9665
9666#ifdef USE_DNSRPS
9667 CHECKFATAL(dns_dnsrps_server_create(),
9668 "initializing RPZ service interface");
9669#endif
9670
9671 /* Initialize server data structures. */
9672 server->interfacemgr = NULL;
9673 ISC_LIST_INIT(server->viewlist);
9674 server->in_roothints = NULL;
9675
9676 /* Must be first. */
9677 CHECKFATAL(dst_lib_init(named_g_mctx, named_g_engine),
9678 "initializing DST");
9679
9680 CHECKFATAL(dns_rootns_create(mctx, dns_rdataclass_in, NULL,
9681 &server->in_roothints),
9682 "setting up root hints");
9683
9684 isc_mutex_init(&server->reload_event_lock);
9685
9686 server->reload_event =
9687 isc_event_allocate(named_g_mctx, server,
9688 NAMED_EVENT_RELOAD,
9689 named_server_reload,
9690 server,
9691 sizeof(isc_event_t));
9692 CHECKFATAL(server->reload_event == NULL ?
9693 ISC_R_NOMEMORY : ISC_R_SUCCESS,
9694 "allocating reload event");
9695 server->reload_in_progress = true;
9696
9697 /*
9698 * Setup the server task, which is responsible for coordinating
9699 * startup and shutdown of the server, as well as all exclusive
9700 * tasks.
9701 */
9702 CHECKFATAL(isc_task_create(named_g_taskmgr, 0, &server->task),
9703 "creating server task");
9704 isc_task_setname(server->task, "server", server);
9705 isc_taskmgr_setexcltask(named_g_taskmgr, server->task);
9706
9707 server->sctx = NULL;
9708 CHECKFATAL(ns_server_create(mctx, get_matching_view,
9709 &server->sctx),
9710 "creating server context");
9711
9712#ifdef HAVE_GEOIP
9713 /*
9714 * GeoIP must be initialized before the interface
9715 * manager (which includes the ACL environment)
9716 * is created
9717 */
9718 named_geoip_init();
9719#endif
9720
9721#ifdef ENABLE_AFL
9722 server->sctx->fuzztype = named_g_fuzz_type;
9723 server->sctx->fuzznotify = named_fuzz_notify;
9724#endif
9725
9726 CHECKFATAL(isc_task_onshutdown(server->task, shutdown_server, server),
9727 "isc_task_onshutdown");
9728 CHECKFATAL(isc_app_onrun(named_g_mctx, server->task,
9729 run_server, server),
9730 "isc_app_onrun");
9731
9732 server->interface_timer = NULL;
9733 server->heartbeat_timer = NULL;
9734 server->pps_timer = NULL;
9735 server->tat_timer = NULL;
9736
9737 server->interface_interval = 0;
9738 server->heartbeat_interval = 0;
9739
9740 CHECKFATAL(dns_zonemgr_create(named_g_mctx, named_g_taskmgr,
9741 named_g_timermgr, named_g_socketmgr,
9742 &server->zonemgr),
9743 "dns_zonemgr_create");
9744 CHECKFATAL(dns_zonemgr_setsize(server->zonemgr, 1000),
9745 "dns_zonemgr_setsize");
9746
9747 server->statsfile = isc_mem_strdup(server->mctx, "named.stats");
9748 CHECKFATAL(server->statsfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
9749 "isc_mem_strdup");
9750
9751 server->bindkeysfile = isc_mem_strdup(server->mctx,
9752 named_g_defaultbindkeys);
9753 CHECKFATAL(server->bindkeysfile == NULL ? ISC_R_NOMEMORY :
9754 ISC_R_SUCCESS,
9755 "isc_mem_strdup");
9756
9757 server->dumpfile = isc_mem_strdup(server->mctx, "named_dump.db");
9758 CHECKFATAL(server->dumpfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
9759 "isc_mem_strdup");
9760
9761 server->secrootsfile = isc_mem_strdup(server->mctx, "named.secroots");
9762 CHECKFATAL(server->secrootsfile == NULL ? ISC_R_NOMEMORY :
9763 ISC_R_SUCCESS,
9764 "isc_mem_strdup");
9765
9766 server->recfile = isc_mem_strdup(server->mctx, "named.recursing");
9767 CHECKFATAL(server->recfile == NULL ? ISC_R_NOMEMORY : ISC_R_SUCCESS,
9768 "isc_mem_strdup");
9769
9770 server->hostname_set = false;
9771 server->hostname = NULL;
9772 server->version_set = false;
9773 server->version = NULL;
9774
9775 server->zonestats = NULL;
9776 server->resolverstats = NULL;
9777 server->sockstats = NULL;
9778 CHECKFATAL(isc_stats_create(server->mctx, &server->sockstats,
9779 isc_sockstatscounter_max),
9780 "isc_stats_create");
9781 isc_socketmgr_setstats(named_g_socketmgr, server->sockstats);
9782
9783 CHECKFATAL(isc_stats_create(named_g_mctx, &server->zonestats,
9784 dns_zonestatscounter_max),
9785 "dns_stats_create (zone)");
9786
9787 CHECKFATAL(isc_stats_create(named_g_mctx, &server->resolverstats,
9788 dns_resstatscounter_max),
9789 "dns_stats_create (resolver)");
9790
9791 server->flushonshutdown = false;
9792
9793 server->controls = NULL;
9794 CHECKFATAL(named_controls_create(server, &server->controls),
9795 "named_controls_create");
9796 server->dispatchgen = 0;
9797 ISC_LIST_INIT(server->dispatches);
9798
9799 ISC_LIST_INIT(server->statschannels);
9800
9801 ISC_LIST_INIT(server->cachelist);
9802
9803 server->sessionkey = NULL;
9804 server->session_keyfile = NULL;
9805 server->session_keyname = NULL;
9806 server->session_keyalg = DST_ALG_UNKNOWN;
9807 server->session_keybits = 0;
9808
9809 server->lockfile = NULL;
9810
9811 server->dtenv = NULL;
9812
9813 server->magic = NAMED_SERVER_MAGIC;
9814 *serverp = server;
9815}
9816
9817void
9818named_server_destroy(named_server_t **serverp) {
9819 named_server_t *server = *serverp;
9820 REQUIRE(NAMED_SERVER_VALID(server));
9821
9822#ifdef HAVE_DNSTAP
9823 if (server->dtenv != NULL)
9824 dns_dt_detach(&server->dtenv);
9825#endif /* HAVE_DNSTAP */
9826
9827#ifdef USE_DNSRPS
9828 dns_dnsrps_server_destroy();
9829#endif
9830
9831 named_controls_destroy(&server->controls);
9832
9833 isc_stats_detach(&server->zonestats);
9834 isc_stats_detach(&server->sockstats);
9835 isc_stats_detach(&server->resolverstats);
9836
9837 if (server->sctx != NULL)
9838 ns_server_detach(&server->sctx);
9839
9840 isc_mem_free(server->mctx, server->statsfile);
9841 isc_mem_free(server->mctx, server->bindkeysfile);
9842 isc_mem_free(server->mctx, server->dumpfile);
9843 isc_mem_free(server->mctx, server->secrootsfile);
9844 isc_mem_free(server->mctx, server->recfile);
9845
9846 if (server->version != NULL)
9847 isc_mem_free(server->mctx, server->version);
9848 if (server->hostname != NULL)
9849 isc_mem_free(server->mctx, server->hostname);
9850 if (server->lockfile != NULL)
9851 isc_mem_free(server->mctx, server->lockfile);
9852
9853 if (server->zonemgr != NULL)
9854 dns_zonemgr_detach(&server->zonemgr);
9855
9856 dst_lib_destroy();
9857
9858 isc_event_free(&server->reload_event);
9859
9860 INSIST(ISC_LIST_EMPTY(server->viewlist));
9861 INSIST(ISC_LIST_EMPTY(server->cachelist));
9862
9863 server->magic = 0;
9864 isc_mem_put(server->mctx, server, sizeof(*server));
9865 *serverp = NULL;
9866}
9867
9868static void
9869fatal(const char *msg, isc_result_t result) {
9870 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9871 NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
9872 "%s: %s", msg, isc_result_totext(result));
9873 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9874 NAMED_LOGMODULE_SERVER, ISC_LOG_CRITICAL,
9875 "exiting (due to fatal error)");
9876 named_os_shutdown();
9877 exit(1);
9878}
9879
9880static void
9881start_reserved_dispatches(named_server_t *server) {
9882
9883 REQUIRE(NAMED_SERVER_VALID(server));
9884
9885 server->dispatchgen++;
9886}
9887
9888static void
9889end_reserved_dispatches(named_server_t *server, bool all) {
9890 named_dispatch_t *dispatch, *nextdispatch;
9891
9892 REQUIRE(NAMED_SERVER_VALID(server));
9893
9894 for (dispatch = ISC_LIST_HEAD(server->dispatches);
9895 dispatch != NULL;
9896 dispatch = nextdispatch) {
9897 nextdispatch = ISC_LIST_NEXT(dispatch, link);
9898 if (!all && server->dispatchgen == dispatch-> dispatchgen)
9899 continue;
9900 ISC_LIST_UNLINK(server->dispatches, dispatch, link);
9901 dns_dispatch_detach(&dispatch->dispatch);
9902 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
9903 }
9904}
9905
9906void
9907named_add_reserved_dispatch(named_server_t *server,
9908 const isc_sockaddr_t *addr)
9909{
9910 named_dispatch_t *dispatch;
9911 in_port_t port;
9912 char addrbuf[ISC_SOCKADDR_FORMATSIZE];
9913 isc_result_t result;
9914 unsigned int attrs, attrmask;
9915
9916 REQUIRE(NAMED_SERVER_VALID(server));
9917
9918 port = isc_sockaddr_getport(addr);
9919 if (port == 0 || port >= 1024)
9920 return;
9921
9922 for (dispatch = ISC_LIST_HEAD(server->dispatches);
9923 dispatch != NULL;
9924 dispatch = ISC_LIST_NEXT(dispatch, link)) {
9925 if (isc_sockaddr_equal(&dispatch->addr, addr))
9926 break;
9927 }
9928 if (dispatch != NULL) {
9929 dispatch->dispatchgen = server->dispatchgen;
9930 return;
9931 }
9932
9933 dispatch = isc_mem_get(server->mctx, sizeof(*dispatch));
9934 if (dispatch == NULL) {
9935 result = ISC_R_NOMEMORY;
9936 goto cleanup;
9937 }
9938
9939 dispatch->addr = *addr;
9940 dispatch->dispatchgen = server->dispatchgen;
9941 dispatch->dispatch = NULL;
9942
9943 attrs = 0;
9944 attrs |= DNS_DISPATCHATTR_UDP;
9945 switch (isc_sockaddr_pf(addr)) {
9946 case AF_INET:
9947 attrs |= DNS_DISPATCHATTR_IPV4;
9948 break;
9949 case AF_INET6:
9950 attrs |= DNS_DISPATCHATTR_IPV6;
9951 break;
9952 default:
9953 result = ISC_R_NOTIMPLEMENTED;
9954 goto cleanup;
9955 }
9956 attrmask = 0;
9957 attrmask |= DNS_DISPATCHATTR_UDP;
9958 attrmask |= DNS_DISPATCHATTR_TCP;
9959 attrmask |= DNS_DISPATCHATTR_IPV4;
9960 attrmask |= DNS_DISPATCHATTR_IPV6;
9961
9962 result = dns_dispatch_getudp(named_g_dispatchmgr, named_g_socketmgr,
9963 named_g_taskmgr, &dispatch->addr, 4096,
9964 UDPBUFFERS, 32768, 16411, 16433,
9965 attrs, attrmask, &dispatch->dispatch);
9966 if (result != ISC_R_SUCCESS)
9967 goto cleanup;
9968
9969 ISC_LIST_INITANDPREPEND(server->dispatches, dispatch, link);
9970
9971 return;
9972
9973 cleanup:
9974 if (dispatch != NULL)
9975 isc_mem_put(server->mctx, dispatch, sizeof(*dispatch));
9976 isc_sockaddr_format(addr, addrbuf, sizeof(addrbuf));
9977 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9978 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
9979 "unable to create dispatch for reserved port %s: %s",
9980 addrbuf, isc_result_totext(result));
9981}
9982
9983
9984static isc_result_t
9985loadconfig(named_server_t *server) {
9986 isc_result_t result;
9987 start_reserved_dispatches(server);
9988 result = load_configuration(named_g_conffile, server, false);
9989 if (result == ISC_R_SUCCESS) {
9990 end_reserved_dispatches(server, false);
9991 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9992 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
9993 "reloading configuration succeeded");
9994 } else {
9995 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
9996 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
9997 "reloading configuration failed: %s",
9998 isc_result_totext(result));
9999 }
10000
10001 return (result);
10002}
10003
10004static isc_result_t
10005reload(named_server_t *server) {
10006 isc_result_t result;
10007 server->reload_in_progress = true;
10008 CHECK(loadconfig(server));
10009
10010 result = load_zones(server, false, false);
10011 if (result == ISC_R_SUCCESS)
10012 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10013 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10014 "reloading zones succeeded");
10015 else
10016 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10017 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10018 "reloading zones failed: %s",
10019 isc_result_totext(result));
10020
10021 cleanup:
10022 return (result);
10023}
10024
10025/*
10026 * Handle a reload event (from SIGHUP).
10027 */
10028static void
10029named_server_reload(isc_task_t *task, isc_event_t *event) {
10030 named_server_t *server = (named_server_t *)event->ev_arg;
10031
10032 INSIST(task == server->task);
10033 UNUSED(task);
10034
10035 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10036 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10037 "received SIGHUP signal to reload zones");
10038 (void)reload(server);
10039
10040 LOCK(&server->reload_event_lock);
10041 INSIST(server->reload_event == NULL);
10042 server->reload_event = event;
10043 UNLOCK(&server->reload_event_lock);
10044}
10045
10046void
10047named_server_reloadwanted(named_server_t *server) {
10048 LOCK(&server->reload_event_lock);
10049 if (server->reload_event != NULL)
10050 isc_task_send(server->task, &server->reload_event);
10051 UNLOCK(&server->reload_event_lock);
10052}
10053
10054void
10055named_server_scan_interfaces(named_server_t *server) {
10056 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10057 NAMED_LOGMODULE_SERVER, ISC_LOG_DEBUG(1),
10058 "automatic interface rescan");
10059
10060 ns_interfacemgr_scan(server->interfacemgr, true);
10061}
10062
10063/*
10064 * Get the next token from lexer 'lex'.
10065 *
10066 * NOTE: the token value for string tokens always uses the same pointer
10067 * value. Multiple calls to this function on the same lexer will always
10068 * return either that value (lex->data) or NULL. It is necessary to copy
10069 * the token into local storage if it needs to be referenced after the next
10070 * call to next_token().
10071 */
10072static char *
10073next_token(isc_lex_t *lex, isc_buffer_t **text) {
10074 isc_result_t result;
10075 isc_token_t token;
10076
10077 token.type = isc_tokentype_unknown;
10078 result = isc_lex_gettoken(lex, ISC_LEXOPT_EOF|ISC_LEXOPT_QSTRING,
10079 &token);
10080
10081 switch (result) {
10082 case ISC_R_NOMORE:
10083 (void) isc_lex_close(lex);
10084 break;
10085 case ISC_R_SUCCESS:
10086 if (token.type == isc_tokentype_eof)
10087 (void) isc_lex_close(lex);
10088 break;
10089 case ISC_R_NOSPACE:
10090 if (text != NULL) {
10091 (void) putstr(text, "token too large");
10092 (void) putnull(text);
10093 }
10094 return (NULL);
10095 default:
10096 if (text != NULL) {
10097 (void) putstr(text, isc_result_totext(result));
10098 (void) putnull(text);
10099 }
10100 return (NULL);
10101 }
10102
10103 if (token.type == isc_tokentype_string ||
10104 token.type == isc_tokentype_qstring)
10105 return (token.value.as_textregion.base);
10106
10107 return (NULL);
10108}
10109
10110/*
10111 * Find the zone specified in the control channel command, if any.
10112 * If a zone is specified, point '*zonep' at it, otherwise
10113 * set '*zonep' to NULL, and f 'zonename' is not NULL, copy
10114 * the zone name into it (N.B. 'zonename' must have space to hold
10115 * a full DNS name).
10116 *
10117 * If 'zonetxt' is set, the caller has already pulled a token
10118 * off the command line that is to be used as the zone name. (This
10119 * is sometimes done when it's necessary to check for an optional
10120 * argument before the zone name, as in "rndc sync [-clean] zone".)
10121 */
10122static isc_result_t
10123zone_from_args(named_server_t *server, isc_lex_t *lex, const char *zonetxt,
10124 dns_zone_t **zonep, char *zonename,
10125 isc_buffer_t **text, bool skip)
10126{
10127 char *ptr;
10128 char *classtxt;
10129 const char *viewtxt = NULL;
10130 dns_fixedname_t fname;
10131 dns_name_t *name;
10132 isc_result_t result;
10133 dns_view_t *view = NULL;
10134 dns_rdataclass_t rdclass;
10135 char problem[DNS_NAME_FORMATSIZE + 500] = "";
10136 char zonebuf[DNS_NAME_FORMATSIZE];
10137 bool redirect = false;
10138
10139 REQUIRE(zonep != NULL && *zonep == NULL);
10140
10141 if (skip) {
10142 /* Skip the command name. */
10143 ptr = next_token(lex, text);
10144 if (ptr == NULL)
10145 return (ISC_R_UNEXPECTEDEND);
10146 }
10147
10148 /* Look for the zone name. */
10149 if (zonetxt == NULL)
10150 zonetxt = next_token(lex, text);
10151 if (zonetxt == NULL)
10152 return (ISC_R_SUCCESS);
10153
10154 /* Copy zonetxt because it'll be overwritten by next_token() */
10155 /* To locate a zone named "-redirect" use "-redirect." */
10156 if (strcmp(zonetxt, "-redirect") == 0) {
10157 redirect = true;
10158 strlcpy(zonebuf, ".", DNS_NAME_FORMATSIZE);
10159 } else
10160 strlcpy(zonebuf, zonetxt, DNS_NAME_FORMATSIZE);
10161 if (zonename != NULL)
10162 strlcpy(zonename, redirect ? "." : zonetxt,
10163 DNS_NAME_FORMATSIZE);
10164
10165 name = dns_fixedname_initname(&fname);
10166 CHECK(dns_name_fromstring(name, zonebuf, 0, NULL));
10167
10168 /* Look for the optional class name. */
10169 classtxt = next_token(lex, text);
10170 if (classtxt != NULL) {
10171 isc_textregion_t r;
10172 r.base = classtxt;
10173 r.length = strlen(classtxt);
10174 CHECK(dns_rdataclass_fromtext(&rdclass, &r));
10175
10176 /* Look for the optional view name. */
10177 viewtxt = next_token(lex, text);
10178 } else
10179 rdclass = dns_rdataclass_in;
10180
10181 if (viewtxt == NULL) {
10182 if (redirect) {
10183 result = dns_viewlist_find(&server->viewlist,
10184 "_default",
10185 dns_rdataclass_in,
10186 &view);
10187 if (result != ISC_R_SUCCESS ||
10188 view->redirect == NULL)
10189 {
10190 result = ISC_R_NOTFOUND;
10191 snprintf(problem, sizeof(problem),
10192 "redirect zone not found in "
10193 "_default view");
10194 } else {
10195 dns_zone_attach(view->redirect, zonep);
10196 result = ISC_R_SUCCESS;
10197 }
10198 } else {
10199 result = dns_viewlist_findzone(&server->viewlist,
10200 name, (classtxt == NULL),
10201 rdclass, zonep);
10202 if (result == ISC_R_NOTFOUND)
10203 snprintf(problem, sizeof(problem),
10204 "no matching zone '%s' in any view",
10205 zonebuf);
10206 else if (result == ISC_R_MULTIPLE)
10207 snprintf(problem, sizeof(problem),
10208 "zone '%s' was found in multiple "
10209 "views", zonebuf);
10210 }
10211 } else {
10212 result = dns_viewlist_find(&server->viewlist, viewtxt,
10213 rdclass, &view);
10214 if (result != ISC_R_SUCCESS) {
10215 snprintf(problem, sizeof(problem),
10216 "no matching view '%s'", viewtxt);
10217 goto report;
10218 }
10219
10220 if (redirect) {
10221 if (view->redirect != NULL) {
10222 dns_zone_attach(view->redirect, zonep);
10223 result = ISC_R_SUCCESS;
10224 } else
10225 result = ISC_R_NOTFOUND;
10226 } else
10227 result = dns_zt_find(view->zonetable, name, 0,
10228 NULL, zonep);
10229 if (result != ISC_R_SUCCESS)
10230 snprintf(problem, sizeof(problem),
10231 "no matching zone '%s' in view '%s'",
10232 zonebuf, viewtxt);
10233 }
10234
10235 /* Partial match? */
10236 if (result != ISC_R_SUCCESS && *zonep != NULL)
10237 dns_zone_detach(zonep);
10238 if (result == DNS_R_PARTIALMATCH)
10239 result = ISC_R_NOTFOUND;
10240 report:
10241 if (result != ISC_R_SUCCESS) {
10242 isc_result_t tresult;
10243
10244 tresult = putstr(text, problem);
10245 if (tresult == ISC_R_SUCCESS)
10246 (void) putnull(text);
10247 }
10248
10249 cleanup:
10250 if (view != NULL)
10251 dns_view_detach(&view);
10252
10253 return (result);
10254}
10255
10256/*
10257 * Act on a "retransfer" command from the command channel.
10258 */
10259isc_result_t
10260named_server_retransfercommand(named_server_t *server, isc_lex_t *lex,
10261 isc_buffer_t **text)
10262{
10263 isc_result_t result;
10264 dns_zone_t *zone = NULL;
10265 dns_zone_t *raw = NULL;
10266 dns_zonetype_t type;
10267
10268 result = zone_from_args(server, lex, NULL, &zone, NULL,
10269 text, true);
10270 if (result != ISC_R_SUCCESS)
10271 return (result);
10272 if (zone == NULL)
10273 return (ISC_R_UNEXPECTEDEND);
10274 dns_zone_getraw(zone, &raw);
10275 if (raw != NULL) {
10276 dns_zone_detach(&zone);
10277 dns_zone_attach(raw, &zone);
10278 dns_zone_detach(&raw);
10279 }
10280 type = dns_zone_gettype(zone);
10281 if (type == dns_zone_slave || type == dns_zone_mirror ||
10282 type == dns_zone_stub ||
10283 (type == dns_zone_redirect &&
10284 dns_zone_getredirecttype(zone) == dns_zone_slave))
10285 dns_zone_forcereload(zone);
10286 else
10287 result = ISC_R_NOTFOUND;
10288 dns_zone_detach(&zone);
10289 return (result);
10290}
10291
10292/*
10293 * Act on a "reload" command from the command channel.
10294 */
10295isc_result_t
10296named_server_reloadcommand(named_server_t *server, isc_lex_t *lex,
10297 isc_buffer_t **text)
10298{
10299 isc_result_t result;
10300 dns_zone_t *zone = NULL;
10301 dns_zonetype_t type;
10302 const char *msg = NULL;
10303
10304 result = zone_from_args(server, lex, NULL, &zone, NULL,
10305 text, true);
10306 if (result != ISC_R_SUCCESS)
10307 return (result);
10308 if (zone == NULL) {
10309 result = reload(server);
10310 if (result == ISC_R_SUCCESS)
10311 msg = "server reload successful";
10312 } else {
10313 type = dns_zone_gettype(zone);
10314 if (type == dns_zone_slave || type == dns_zone_mirror ||
10315 type == dns_zone_stub)
10316 {
10317 dns_zone_refresh(zone);
10318 dns_zone_detach(&zone);
10319 msg = "zone refresh queued";
10320 } else {
10321 result = dns_zone_load(zone, false);
10322 dns_zone_detach(&zone);
10323 switch (result) {
10324 case ISC_R_SUCCESS:
10325 msg = "zone reload successful";
10326 break;
10327 case DNS_R_CONTINUE:
10328 msg = "zone reload queued";
10329 result = ISC_R_SUCCESS;
10330 break;
10331 case DNS_R_UPTODATE:
10332 msg = "zone reload up-to-date";
10333 result = ISC_R_SUCCESS;
10334 break;
10335 default:
10336 /* failure message will be generated by rndc */
10337 break;
10338 }
10339 }
10340 }
10341 if (msg != NULL) {
10342 (void) putstr(text, msg);
10343 (void) putnull(text);
10344 }
10345 return (result);
10346}
10347
10348/*
10349 * Act on a "reconfig" command from the command channel.
10350 */
10351isc_result_t
10352named_server_reconfigcommand(named_server_t *server) {
10353 isc_result_t result;
10354 server->reload_in_progress = true;
10355
10356 CHECK(loadconfig(server));
10357
10358 result = load_zones(server, false, true);
10359 if (result == ISC_R_SUCCESS)
10360 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10361 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10362 "scheduled loading new zones");
10363 else
10364 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10365 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10366 "loading new zones failed: %s",
10367 isc_result_totext(result));
10368cleanup:
10369 return (result);
10370}
10371
10372/*
10373 * Act on a "notify" command from the command channel.
10374 */
10375isc_result_t
10376named_server_notifycommand(named_server_t *server, isc_lex_t *lex,
10377 isc_buffer_t **text)
10378{
10379 isc_result_t result;
10380 dns_zone_t *zone = NULL;
10381 const char msg[] = "zone notify queued";
10382
10383 result = zone_from_args(server, lex, NULL, &zone, NULL,
10384 text, true);
10385 if (result != ISC_R_SUCCESS)
10386 return (result);
10387 if (zone == NULL)
10388 return (ISC_R_UNEXPECTEDEND);
10389
10390 dns_zone_notify(zone);
10391 dns_zone_detach(&zone);
10392 (void) putstr(text, msg);
10393 (void) putnull(text);
10394
10395 return (ISC_R_SUCCESS);
10396}
10397
10398/*
10399 * Act on a "refresh" command from the command channel.
10400 */
10401isc_result_t
10402named_server_refreshcommand(named_server_t *server, isc_lex_t *lex,
10403 isc_buffer_t **text)
10404{
10405 isc_result_t result;
10406 dns_zone_t *zone = NULL, *raw = NULL;
10407 const char msg1[] = "zone refresh queued";
10408 const char msg2[] = "not a slave, mirror, or stub zone";
10409 dns_zonetype_t type;
10410
10411 result = zone_from_args(server, lex, NULL, &zone, NULL,
10412 text, true);
10413 if (result != ISC_R_SUCCESS)
10414 return (result);
10415 if (zone == NULL)
10416 return (ISC_R_UNEXPECTEDEND);
10417
10418 dns_zone_getraw(zone, &raw);
10419 if (raw != NULL) {
10420 dns_zone_detach(&zone);
10421 dns_zone_attach(raw, &zone);
10422 dns_zone_detach(&raw);
10423 }
10424
10425 type = dns_zone_gettype(zone);
10426 if (type == dns_zone_slave || type == dns_zone_mirror ||
10427 type == dns_zone_stub)
10428 {
10429 dns_zone_refresh(zone);
10430 dns_zone_detach(&zone);
10431 (void) putstr(text, msg1);
10432 (void) putnull(text);
10433 return (ISC_R_SUCCESS);
10434 }
10435
10436 dns_zone_detach(&zone);
10437 (void) putstr(text, msg2);
10438 (void) putnull(text);
10439 return (ISC_R_FAILURE);
10440}
10441
10442isc_result_t
10443named_server_togglequerylog(named_server_t *server, isc_lex_t *lex) {
10444 bool prev, value;
10445 char *ptr;
10446
10447 /* Skip the command name. */
10448 ptr = next_token(lex, NULL);
10449 if (ptr == NULL)
10450 return (ISC_R_UNEXPECTEDEND);
10451
10452 prev = ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES);
10453
10454 ptr = next_token(lex, NULL);
10455 if (ptr == NULL) {
10456 value = !prev;
10457 } else if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
10458 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) {
10459 value = true;
10460 } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
10461 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) {
10462 value = false;
10463 } else {
10464 return (DNS_R_SYNTAX);
10465 }
10466
10467 if (value == prev)
10468 return (ISC_R_SUCCESS);
10469
10470 ns_server_setoption(server->sctx, NS_SERVER_LOGQUERIES, value);
10471
10472 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10473 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10474 "query logging is now %s", value ? "on" : "off");
10475 return (ISC_R_SUCCESS);
10476}
10477
10478static isc_result_t
10479ns_listenlist_fromconfig(const cfg_obj_t *listenlist, const cfg_obj_t *config,
10480 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
10481 uint16_t family, ns_listenlist_t **target)
10482{
10483 isc_result_t result;
10484 const cfg_listelt_t *element;
10485 ns_listenlist_t *dlist = NULL;
10486
10487 REQUIRE(target != NULL && *target == NULL);
10488
10489 result = ns_listenlist_create(mctx, &dlist);
10490 if (result != ISC_R_SUCCESS)
10491 return (result);
10492
10493 for (element = cfg_list_first(listenlist);
10494 element != NULL;
10495 element = cfg_list_next(element))
10496 {
10497 ns_listenelt_t *delt = NULL;
10498 const cfg_obj_t *listener = cfg_listelt_value(element);
10499 result = ns_listenelt_fromconfig(listener, config, actx,
10500 mctx, family, &delt);
10501 if (result != ISC_R_SUCCESS)
10502 goto cleanup;
10503 ISC_LIST_APPEND(dlist->elts, delt, link);
10504 }
10505 *target = dlist;
10506 return (ISC_R_SUCCESS);
10507
10508 cleanup:
10509 ns_listenlist_detach(&dlist);
10510 return (result);
10511}
10512
10513/*
10514 * Create a listen list from the corresponding configuration
10515 * data structure.
10516 */
10517static isc_result_t
10518ns_listenelt_fromconfig(const cfg_obj_t *listener, const cfg_obj_t *config,
10519 cfg_aclconfctx_t *actx, isc_mem_t *mctx,
10520 uint16_t family, ns_listenelt_t **target)
10521{
10522 isc_result_t result;
10523 const cfg_obj_t *portobj, *dscpobj;
10524 in_port_t port;
10525 isc_dscp_t dscp = -1;
10526 ns_listenelt_t *delt = NULL;
10527 REQUIRE(target != NULL && *target == NULL);
10528
10529 portobj = cfg_tuple_get(listener, "port");
10530 if (!cfg_obj_isuint32(portobj)) {
10531 if (named_g_port != 0) {
10532 port = named_g_port;
10533 } else {
10534 result = named_config_getport(config, &port);
10535 if (result != ISC_R_SUCCESS)
10536 return (result);
10537 }
10538 } else {
10539 if (cfg_obj_asuint32(portobj) >= UINT16_MAX) {
10540 cfg_obj_log(portobj, named_g_lctx, ISC_LOG_ERROR,
10541 "port value '%u' is out of range",
10542 cfg_obj_asuint32(portobj));
10543 return (ISC_R_RANGE);
10544 }
10545 port = (in_port_t)cfg_obj_asuint32(portobj);
10546 }
10547
10548 dscpobj = cfg_tuple_get(listener, "dscp");
10549 if (!cfg_obj_isuint32(dscpobj))
10550 dscp = named_g_dscp;
10551 else {
10552 if (cfg_obj_asuint32(dscpobj) > 63) {
10553 cfg_obj_log(dscpobj, named_g_lctx, ISC_LOG_ERROR,
10554 "dscp value '%u' is out of range",
10555 cfg_obj_asuint32(dscpobj));
10556 return (ISC_R_RANGE);
10557 }
10558 dscp = (isc_dscp_t)cfg_obj_asuint32(dscpobj);
10559 }
10560
10561 result = ns_listenelt_create(mctx, port, dscp, NULL, &delt);
10562 if (result != ISC_R_SUCCESS)
10563 return (result);
10564
10565 result = cfg_acl_fromconfig2(cfg_tuple_get(listener, "acl"),
10566 config, named_g_lctx, actx, mctx, 0,
10567 family, &delt->acl);
10568 if (result != ISC_R_SUCCESS) {
10569 ns_listenelt_destroy(delt);
10570 return (result);
10571 }
10572 *target = delt;
10573 return (ISC_R_SUCCESS);
10574}
10575
10576isc_result_t
10577named_server_dumpstats(named_server_t *server) {
10578 isc_result_t result;
10579 FILE *fp = NULL;
10580
10581 CHECKMF(isc_stdio_open(server->statsfile, "a", &fp),
10582 "could not open statistics dump file", server->statsfile);
10583
10584 result = named_stats_dump(server, fp);
10585
10586 cleanup:
10587 if (fp != NULL)
10588 (void)isc_stdio_close(fp);
10589 if (result == ISC_R_SUCCESS)
10590 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10591 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10592 "dumpstats complete");
10593 else
10594 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10595 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10596 "dumpstats failed: %s",
10597 dns_result_totext(result));
10598 return (result);
10599}
10600
10601static isc_result_t
10602add_zone_tolist(dns_zone_t *zone, void *uap) {
10603 struct dumpcontext *dctx = uap;
10604 struct zonelistentry *zle;
10605
10606 zle = isc_mem_get(dctx->mctx, sizeof *zle);
10607 if (zle == NULL)
10608 return (ISC_R_NOMEMORY);
10609 zle->zone = NULL;
10610 dns_zone_attach(zone, &zle->zone);
10611 ISC_LINK_INIT(zle, link);
10612 ISC_LIST_APPEND(ISC_LIST_TAIL(dctx->viewlist)->zonelist, zle, link);
10613 return (ISC_R_SUCCESS);
10614}
10615
10616static isc_result_t
10617add_view_tolist(struct dumpcontext *dctx, dns_view_t *view) {
10618 struct viewlistentry *vle;
10619 isc_result_t result = ISC_R_SUCCESS;
10620
10621 /*
10622 * Prevent duplicate views.
10623 */
10624 for (vle = ISC_LIST_HEAD(dctx->viewlist);
10625 vle != NULL;
10626 vle = ISC_LIST_NEXT(vle, link))
10627 if (vle->view == view)
10628 return (ISC_R_SUCCESS);
10629
10630 vle = isc_mem_get(dctx->mctx, sizeof *vle);
10631 if (vle == NULL)
10632 return (ISC_R_NOMEMORY);
10633 vle->view = NULL;
10634 dns_view_attach(view, &vle->view);
10635 ISC_LINK_INIT(vle, link);
10636 ISC_LIST_INIT(vle->zonelist);
10637 ISC_LIST_APPEND(dctx->viewlist, vle, link);
10638 if (dctx->dumpzones)
10639 result = dns_zt_apply(view->zonetable, true, NULL,
10640 add_zone_tolist, dctx);
10641 return (result);
10642}
10643
10644static void
10645dumpcontext_destroy(struct dumpcontext *dctx) {
10646 struct viewlistentry *vle;
10647 struct zonelistentry *zle;
10648
10649 vle = ISC_LIST_HEAD(dctx->viewlist);
10650 while (vle != NULL) {
10651 ISC_LIST_UNLINK(dctx->viewlist, vle, link);
10652 zle = ISC_LIST_HEAD(vle->zonelist);
10653 while (zle != NULL) {
10654 ISC_LIST_UNLINK(vle->zonelist, zle, link);
10655 dns_zone_detach(&zle->zone);
10656 isc_mem_put(dctx->mctx, zle, sizeof *zle);
10657 zle = ISC_LIST_HEAD(vle->zonelist);
10658 }
10659 dns_view_detach(&vle->view);
10660 isc_mem_put(dctx->mctx, vle, sizeof *vle);
10661 vle = ISC_LIST_HEAD(dctx->viewlist);
10662 }
10663 if (dctx->version != NULL)
10664 dns_db_closeversion(dctx->db, &dctx->version, false);
10665 if (dctx->db != NULL)
10666 dns_db_detach(&dctx->db);
10667 if (dctx->cache != NULL)
10668 dns_db_detach(&dctx->cache);
10669 if (dctx->task != NULL)
10670 isc_task_detach(&dctx->task);
10671 if (dctx->fp != NULL)
10672 (void)isc_stdio_close(dctx->fp);
10673 if (dctx->mdctx != NULL)
10674 dns_dumpctx_detach(&dctx->mdctx);
10675 isc_mem_put(dctx->mctx, dctx, sizeof *dctx);
10676}
10677
10678static void
10679dumpdone(void *arg, isc_result_t result) {
10680 struct dumpcontext *dctx = arg;
10681 char buf[1024+32];
10682 const dns_master_style_t *style;
10683
10684 if (result != ISC_R_SUCCESS)
10685 goto cleanup;
10686 if (dctx->mdctx != NULL)
10687 dns_dumpctx_detach(&dctx->mdctx);
10688 if (dctx->view == NULL) {
10689 dctx->view = ISC_LIST_HEAD(dctx->viewlist);
10690 if (dctx->view == NULL)
10691 goto done;
10692 INSIST(dctx->zone == NULL);
10693 } else
10694 goto resume;
10695 nextview:
10696 fprintf(dctx->fp, ";\n; Start view %s\n;\n", dctx->view->view->name);
10697 resume:
10698 if (dctx->dumpcache && dns_view_iscacheshared(dctx->view->view)) {
10699 fprintf(dctx->fp,
10700 ";\n; Cache of view '%s' is shared as '%s'\n",
10701 dctx->view->view->name,
10702 dns_cache_getname(dctx->view->view->cache));
10703 } else if (dctx->zone == NULL && dctx->cache == NULL &&
10704 dctx->dumpcache)
10705 {
10706 style = &dns_master_style_cache;
10707 /* start cache dump */
10708 if (dctx->view->view->cachedb != NULL)
10709 dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
10710 if (dctx->cache != NULL) {
10711 fprintf(dctx->fp,
10712 ";\n; Cache dump of view '%s' (cache %s)\n;\n",
10713 dctx->view->view->name,
10714 dns_cache_getname(dctx->view->view->cache));
10715 result = dns_master_dumptostreaminc(dctx->mctx,
10716 dctx->cache, NULL,
10717 style, dctx->fp,
10718 dctx->task,
10719 dumpdone, dctx,
10720 &dctx->mdctx);
10721 if (result == DNS_R_CONTINUE)
10722 return;
10723 if (result == ISC_R_NOTIMPLEMENTED)
10724 fprintf(dctx->fp, "; %s\n",
10725 dns_result_totext(result));
10726 else if (result != ISC_R_SUCCESS)
10727 goto cleanup;
10728 }
10729 }
10730
10731 if ((dctx->dumpadb || dctx->dumpbad || dctx->dumpfail) &&
10732 dctx->cache == NULL && dctx->view->view->cachedb != NULL)
10733 dns_db_attach(dctx->view->view->cachedb, &dctx->cache);
10734
10735 if (dctx->cache != NULL) {
10736 if (dctx->dumpadb)
10737 dns_adb_dump(dctx->view->view->adb, dctx->fp);
10738 if (dctx->dumpbad)
10739 dns_resolver_printbadcache(dctx->view->view->resolver,
10740 dctx->fp);
10741 if (dctx->dumpfail)
10742 dns_badcache_print(dctx->view->view->failcache,
10743 "SERVFAIL cache", dctx->fp);
10744 dns_db_detach(&dctx->cache);
10745 }
10746 if (dctx->dumpzones) {
10747 style = &dns_master_style_full;
10748 nextzone:
10749 if (dctx->version != NULL)
10750 dns_db_closeversion(dctx->db, &dctx->version,
10751 false);
10752 if (dctx->db != NULL)
10753 dns_db_detach(&dctx->db);
10754 if (dctx->zone == NULL)
10755 dctx->zone = ISC_LIST_HEAD(dctx->view->zonelist);
10756 else
10757 dctx->zone = ISC_LIST_NEXT(dctx->zone, link);
10758 if (dctx->zone != NULL) {
10759 /* start zone dump */
10760 dns_zone_name(dctx->zone->zone, buf, sizeof(buf));
10761 fprintf(dctx->fp, ";\n; Zone dump of '%s'\n;\n", buf);
10762 result = dns_zone_getdb(dctx->zone->zone, &dctx->db);
10763 if (result != ISC_R_SUCCESS) {
10764 fprintf(dctx->fp, "; %s\n",
10765 dns_result_totext(result));
10766 goto nextzone;
10767 }
10768 dns_db_currentversion(dctx->db, &dctx->version);
10769 result = dns_master_dumptostreaminc(dctx->mctx,
10770 dctx->db,
10771 dctx->version,
10772 style, dctx->fp,
10773 dctx->task,
10774 dumpdone, dctx,
10775 &dctx->mdctx);
10776 if (result == DNS_R_CONTINUE)
10777 return;
10778 if (result == ISC_R_NOTIMPLEMENTED) {
10779 fprintf(dctx->fp, "; %s\n",
10780 dns_result_totext(result));
10781 result = ISC_R_SUCCESS;
10782 POST(result);
10783 goto nextzone;
10784 }
10785 if (result != ISC_R_SUCCESS)
10786 goto cleanup;
10787 }
10788 }
10789 if (dctx->view != NULL)
10790 dctx->view = ISC_LIST_NEXT(dctx->view, link);
10791 if (dctx->view != NULL)
10792 goto nextview;
10793 done:
10794 fprintf(dctx->fp, "; Dump complete\n");
10795 result = isc_stdio_flush(dctx->fp);
10796 if (result == ISC_R_SUCCESS)
10797 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10798 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10799 "dumpdb complete");
10800 cleanup:
10801 if (result != ISC_R_SUCCESS)
10802 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10803 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
10804 "dumpdb failed: %s", dns_result_totext(result));
10805 dumpcontext_destroy(dctx);
10806}
10807
10808isc_result_t
10809named_server_dumpdb(named_server_t *server, isc_lex_t *lex,
10810 isc_buffer_t **text)
10811{
10812 struct dumpcontext *dctx = NULL;
10813 dns_view_t *view;
10814 isc_result_t result;
10815 char *ptr;
10816 const char *sep;
10817 bool found;
10818
10819 /* Skip the command name. */
10820 ptr = next_token(lex, NULL);
10821 if (ptr == NULL)
10822 return (ISC_R_UNEXPECTEDEND);
10823
10824 dctx = isc_mem_get(server->mctx, sizeof(*dctx));
10825 if (dctx == NULL)
10826 return (ISC_R_NOMEMORY);
10827
10828 dctx->mctx = server->mctx;
10829 dctx->dumpcache = true;
10830 dctx->dumpadb = true;
10831 dctx->dumpbad = true;
10832 dctx->dumpfail = true;
10833 dctx->dumpzones = false;
10834 dctx->fp = NULL;
10835 ISC_LIST_INIT(dctx->viewlist);
10836 dctx->view = NULL;
10837 dctx->zone = NULL;
10838 dctx->cache = NULL;
10839 dctx->mdctx = NULL;
10840 dctx->db = NULL;
10841 dctx->cache = NULL;
10842 dctx->task = NULL;
10843 dctx->version = NULL;
10844 isc_task_attach(server->task, &dctx->task);
10845
10846 CHECKMF(isc_stdio_open(server->dumpfile, "w", &dctx->fp),
10847 "could not open dump file", server->dumpfile);
10848
10849 ptr = next_token(lex, NULL);
10850 sep = (ptr == NULL) ? "" : ": ";
10851 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
10852 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
10853 "dumpdb started%s%s", sep, (ptr != NULL) ? ptr : "");
10854
10855 if (ptr != NULL && strcmp(ptr, "-all") == 0) {
10856 /* also dump zones */
10857 dctx->dumpzones = true;
10858 ptr = next_token(lex, NULL);
10859 } else if (ptr != NULL && strcmp(ptr, "-cache") == 0) {
10860 /* this is the default */
10861 ptr = next_token(lex, NULL);
10862 } else if (ptr != NULL && strcmp(ptr, "-zones") == 0) {
10863 /* only dump zones, suppress caches */
10864 dctx->dumpadb = false;
10865 dctx->dumpbad = false;
10866 dctx->dumpcache = false;
10867 dctx->dumpfail = false;
10868 dctx->dumpzones = true;
10869 ptr = next_token(lex, NULL);
10870 } else if (ptr != NULL && strcmp(ptr, "-adb") == 0) {
10871 /* only dump adb, suppress other caches */
10872 dctx->dumpbad = false;
10873 dctx->dumpcache = false;
10874 dctx->dumpfail = false;
10875 ptr = next_token(lex, NULL);
10876 } else if (ptr != NULL && strcmp(ptr, "-bad") == 0) {
10877 /* only dump badcache, suppress other caches */
10878 dctx->dumpadb = false;
10879 dctx->dumpcache = false;
10880 dctx->dumpfail = false;
10881 ptr = next_token(lex, NULL);
10882 } else if (ptr != NULL && strcmp(ptr, "-fail") == 0) {
10883 /* only dump servfail cache, suppress other caches */
10884 dctx->dumpadb = false;
10885 dctx->dumpbad = false;
10886 dctx->dumpcache = false;
10887 ptr = next_token(lex, NULL);
10888 }
10889
10890 nextview:
10891 found = false;
10892 for (view = ISC_LIST_HEAD(server->viewlist);
10893 view != NULL;
10894 view = ISC_LIST_NEXT(view, link))
10895 {
10896 if (ptr != NULL && strcmp(view->name, ptr) != 0)
10897 continue;
10898 found = true;
10899 CHECK(add_view_tolist(dctx, view));
10900 }
10901 if (ptr != NULL) {
10902 if (!found) {
10903 CHECK(putstr(text, "view '"));
10904 CHECK(putstr(text, ptr));
10905 CHECK(putstr(text, "' not found"));
10906 CHECK(putnull(text));
10907 result = ISC_R_NOTFOUND;
10908 dumpdone(dctx, result);
10909 return (result);
10910 }
10911 ptr = next_token(lex, NULL);
10912 if (ptr != NULL)
10913 goto nextview;
10914 }
10915 dumpdone(dctx, ISC_R_SUCCESS);
10916 return (ISC_R_SUCCESS);
10917
10918 cleanup:
10919 if (dctx != NULL)
10920 dumpcontext_destroy(dctx);
10921 return (result);
10922}
10923
10924isc_result_t
10925named_server_dumpsecroots(named_server_t *server, isc_lex_t *lex,
10926 isc_buffer_t **text)
10927{
10928 dns_view_t *view;
10929 dns_keytable_t *secroots = NULL;
10930 dns_ntatable_t *ntatable = NULL;
10931 isc_result_t result;
10932 char *ptr;
10933 FILE *fp = NULL;
10934 isc_time_t now;
10935 char tbuf[64];
10936
10937 /* Skip the command name. */
10938 ptr = next_token(lex, text);
10939 if (ptr == NULL)
10940 return (ISC_R_UNEXPECTEDEND);
10941
10942 /* "-" here means print the output instead of dumping to file */
10943 ptr = next_token(lex, text);
10944 if (ptr != NULL && strcmp(ptr, "-") == 0)
10945 ptr = next_token(lex, text);
10946 else {
10947 result = isc_stdio_open(server->secrootsfile, "w", &fp);
10948 if (result != ISC_R_SUCCESS) {
10949 (void) putstr(text, "could not open ");
10950 (void) putstr(text, server->secrootsfile);
10951 CHECKMF(result, "could not open secroots dump file",
10952 server->secrootsfile);
10953 }
10954 }
10955
10956 TIME_NOW(&now);
10957 isc_time_formattimestamp(&now, tbuf, sizeof(tbuf));
10958 CHECK(putstr(text, "secure roots as of "));
10959 CHECK(putstr(text, tbuf));
10960 CHECK(putstr(text, ":\n"));
10961
10962 do {
10963 for (view = ISC_LIST_HEAD(server->viewlist);
10964 view != NULL;
10965 view = ISC_LIST_NEXT(view, link))
10966 {
10967 if (ptr != NULL && strcmp(view->name, ptr) != 0)
10968 continue;
10969 if (secroots != NULL)
10970 dns_keytable_detach(&secroots);
10971 result = dns_view_getsecroots(view, &secroots);
10972 if (result == ISC_R_NOTFOUND) {
10973 result = ISC_R_SUCCESS;
10974 continue;
10975 }
10976 CHECK(putstr(text, "\n Start view "));
10977 CHECK(putstr(text, view->name));
10978 CHECK(putstr(text, "\n Secure roots:\n\n"));
10979 CHECK(dns_keytable_totext(secroots, text));
10980
10981 if (ntatable != NULL)
10982 dns_ntatable_detach(&ntatable);
10983 result = dns_view_getntatable(view, &ntatable);
10984 if (result == ISC_R_NOTFOUND) {
10985 result = ISC_R_SUCCESS;
10986 continue;
10987 }
10988 CHECK(putstr(text, "\n Negative trust anchors:\n\n"));
10989 CHECK(dns_ntatable_totext(ntatable, NULL, text));
10990 }
10991 if (ptr != NULL)
10992 ptr = next_token(lex, text);
10993 } while (ptr != NULL);
10994
10995 cleanup:
10996 if (isc_buffer_usedlength(*text) > 0) {
10997 if (fp != NULL)
10998 (void)putstr(text, "\n");
10999 else
11000 (void)putnull(text);
11001 }
11002 if (secroots != NULL)
11003 dns_keytable_detach(&secroots);
11004 if (ntatable != NULL)
11005 dns_ntatable_detach(&ntatable);
11006 if (fp != NULL) {
11007 fprintf(fp, "%.*s", (int) isc_buffer_usedlength(*text),
11008 (char *) isc_buffer_base(*text));
11009 isc_buffer_clear(*text);
11010 (void)isc_stdio_close(fp);
11011 }
11012 if (result == ISC_R_SUCCESS)
11013 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11014 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11015 "dumpsecroots complete");
11016 else
11017 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11018 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11019 "dumpsecroots failed: %s",
11020 dns_result_totext(result));
11021 return (result);
11022}
11023
11024isc_result_t
11025named_server_dumprecursing(named_server_t *server) {
11026 FILE *fp = NULL;
11027 dns_view_t *view;
11028 isc_result_t result;
11029
11030 CHECKMF(isc_stdio_open(server->recfile, "w", &fp),
11031 "could not open dump file", server->recfile);
11032 fprintf(fp, ";\n; Recursing Queries\n;\n");
11033 ns_interfacemgr_dumprecursing(fp, server->interfacemgr);
11034
11035 for (view = ISC_LIST_HEAD(server->viewlist);
11036 view != NULL;
11037 view = ISC_LIST_NEXT(view, link))
11038 {
11039 fprintf(fp, ";\n; Active fetch domains [view: %s]\n;\n",
11040 view->name);
11041 dns_resolver_dumpfetches(view->resolver,
11042 isc_statsformat_file, fp);
11043 }
11044
11045 fprintf(fp, "; Dump complete\n");
11046
11047 cleanup:
11048 if (fp != NULL)
11049 result = isc_stdio_close(fp);
11050 if (result == ISC_R_SUCCESS)
11051 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11052 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11053 "dumprecursing complete");
11054 else
11055 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11056 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11057 "dumprecursing failed: %s",
11058 dns_result_totext(result));
11059 return (result);
11060}
11061
11062isc_result_t
11063named_server_setdebuglevel(named_server_t *server, isc_lex_t *lex) {
11064 char *ptr;
11065 char *endp;
11066 long newlevel;
11067
11068 UNUSED(server);
11069
11070 /* Skip the command name. */
11071 ptr = next_token(lex, NULL);
11072 if (ptr == NULL)
11073 return (ISC_R_UNEXPECTEDEND);
11074
11075 /* Look for the new level name. */
11076 ptr = next_token(lex, NULL);
11077 if (ptr == NULL) {
11078 if (named_g_debuglevel < 99)
11079 named_g_debuglevel++;
11080 } else {
11081 newlevel = strtol(ptr, &endp, 10);
11082 if (*endp != '\0' || newlevel < 0 || newlevel > 99)
11083 return (ISC_R_RANGE);
11084 named_g_debuglevel = (unsigned int)newlevel;
11085 }
11086 isc_log_setdebuglevel(named_g_lctx, named_g_debuglevel);
11087 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11088 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11089 "debug level is now %u", named_g_debuglevel);
11090 return (ISC_R_SUCCESS);
11091}
11092
11093isc_result_t
11094named_server_validation(named_server_t *server, isc_lex_t *lex,
11095 isc_buffer_t **text)
11096{
11097 char *ptr;
11098 dns_view_t *view;
11099 bool changed = false;
11100 isc_result_t result;
11101 bool enable = true, set = true, first = true;
11102
11103 /* Skip the command name. */
11104 ptr = next_token(lex, text);
11105 if (ptr == NULL)
11106 return (ISC_R_UNEXPECTEDEND);
11107
11108 /* Find out what we are to do. */
11109 ptr = next_token(lex, text);
11110 if (ptr == NULL)
11111 return (ISC_R_UNEXPECTEDEND);
11112
11113 if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
11114 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) {
11115 enable = true;
11116 } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
11117 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) {
11118 enable = false;
11119 } else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
11120 set = false;
11121 } else {
11122 return (DNS_R_SYNTAX);
11123 }
11124
11125 /* Look for the view name. */
11126 ptr = next_token(lex, text);
11127
11128 result = isc_task_beginexclusive(server->task);
11129 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11130 for (view = ISC_LIST_HEAD(server->viewlist);
11131 view != NULL;
11132 view = ISC_LIST_NEXT(view, link))
11133 {
11134 if (ptr != NULL && strcasecmp(ptr, view->name) != 0)
11135 continue;
11136 CHECK(dns_view_flushcache(view, false));
11137
11138 if (set) {
11139 view->enablevalidation = enable;
11140 changed = true;
11141 } else {
11142 if (!first)
11143 CHECK(putstr(text, "\n"));
11144 CHECK(putstr(text, "DNSSEC validation is "));
11145 CHECK(putstr(text, view->enablevalidation
11146 ? "enabled" : "disabled"));
11147 CHECK(putstr(text, " (view "));
11148 CHECK(putstr(text, view->name));
11149 CHECK(putstr(text, ")"));
11150 CHECK(putnull(text));
11151 first = false;
11152 }
11153 }
11154
11155 if (!set)
11156 result = ISC_R_SUCCESS;
11157 else if (changed)
11158 result = ISC_R_SUCCESS;
11159 else
11160 result = ISC_R_FAILURE;
11161 cleanup:
11162 isc_task_endexclusive(server->task);
11163 return (result);
11164}
11165
11166isc_result_t
11167named_server_flushcache(named_server_t *server, isc_lex_t *lex) {
11168 char *ptr;
11169 dns_view_t *view;
11170 bool flushed;
11171 bool found;
11172 isc_result_t result;
11173 named_cache_t *nsc;
11174
11175 /* Skip the command name. */
11176 ptr = next_token(lex, NULL);
11177 if (ptr == NULL)
11178 return (ISC_R_UNEXPECTEDEND);
11179
11180 /* Look for the view name. */
11181 ptr = next_token(lex, NULL);
11182
11183 result = isc_task_beginexclusive(server->task);
11184 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11185 flushed = true;
11186 found = false;
11187
11188 /*
11189 * Flushing a cache is tricky when caches are shared by multiple views.
11190 * We first identify which caches should be flushed in the local cache
11191 * list, flush these caches, and then update other views that refer to
11192 * the flushed cache DB.
11193 */
11194 if (ptr != NULL) {
11195 /*
11196 * Mark caches that need to be flushed. This is an O(#view^2)
11197 * operation in the very worst case, but should be normally
11198 * much more lightweight because only a few (most typically just
11199 * one) views will match.
11200 */
11201 for (view = ISC_LIST_HEAD(server->viewlist);
11202 view != NULL;
11203 view = ISC_LIST_NEXT(view, link))
11204 {
11205 if (strcasecmp(ptr, view->name) != 0)
11206 continue;
11207 found = true;
11208 for (nsc = ISC_LIST_HEAD(server->cachelist);
11209 nsc != NULL;
11210 nsc = ISC_LIST_NEXT(nsc, link)) {
11211 if (nsc->cache == view->cache)
11212 break;
11213 }
11214 INSIST(nsc != NULL);
11215 nsc->needflush = true;
11216 }
11217 } else
11218 found = true;
11219
11220 /* Perform flush */
11221 for (nsc = ISC_LIST_HEAD(server->cachelist);
11222 nsc != NULL;
11223 nsc = ISC_LIST_NEXT(nsc, link)) {
11224 if (ptr != NULL && !nsc->needflush)
11225 continue;
11226 nsc->needflush = true;
11227 result = dns_view_flushcache(nsc->primaryview, false);
11228 if (result != ISC_R_SUCCESS) {
11229 flushed = false;
11230 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11231 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11232 "flushing cache in view '%s' failed: %s",
11233 nsc->primaryview->name,
11234 isc_result_totext(result));
11235 }
11236 }
11237
11238 /*
11239 * Fix up views that share a flushed cache: let the views update the
11240 * cache DB they're referring to. This could also be an expensive
11241 * operation, but should typically be marginal: the inner loop is only
11242 * necessary for views that share a cache, and if there are many such
11243 * views the number of shared cache should normally be small.
11244 * A worst case is that we have n views and n/2 caches, each shared by
11245 * two views. Then this will be a O(n^2/4) operation.
11246 */
11247 for (view = ISC_LIST_HEAD(server->viewlist);
11248 view != NULL;
11249 view = ISC_LIST_NEXT(view, link))
11250 {
11251 if (!dns_view_iscacheshared(view))
11252 continue;
11253 for (nsc = ISC_LIST_HEAD(server->cachelist);
11254 nsc != NULL;
11255 nsc = ISC_LIST_NEXT(nsc, link)) {
11256 if (!nsc->needflush || nsc->cache != view->cache)
11257 continue;
11258 result = dns_view_flushcache(view, true);
11259 if (result != ISC_R_SUCCESS) {
11260 flushed = false;
11261 isc_log_write(named_g_lctx,
11262 NAMED_LOGCATEGORY_GENERAL,
11263 NAMED_LOGMODULE_SERVER,
11264 ISC_LOG_ERROR,
11265 "fixing cache in view '%s' "
11266 "failed: %s", view->name,
11267 isc_result_totext(result));
11268 }
11269 }
11270 }
11271
11272 /* Cleanup the cache list. */
11273 for (nsc = ISC_LIST_HEAD(server->cachelist);
11274 nsc != NULL;
11275 nsc = ISC_LIST_NEXT(nsc, link)) {
11276 nsc->needflush = false;
11277 }
11278
11279 if (flushed && found) {
11280 if (ptr != NULL)
11281 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11282 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11283 "flushing cache in view '%s' succeeded",
11284 ptr);
11285 else
11286 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11287 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11288 "flushing caches in all views succeeded");
11289 result = ISC_R_SUCCESS;
11290 } else {
11291 if (!found) {
11292 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11293 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11294 "flushing cache in view '%s' failed: "
11295 "view not found", ptr);
11296 result = ISC_R_NOTFOUND;
11297 } else
11298 result = ISC_R_FAILURE;
11299 }
11300 isc_task_endexclusive(server->task);
11301 return (result);
11302}
11303
11304isc_result_t
11305named_server_flushnode(named_server_t *server, isc_lex_t *lex,
11306 bool tree)
11307{
11308 char *ptr, *viewname;
11309 char target[DNS_NAME_FORMATSIZE];
11310 dns_view_t *view;
11311 bool flushed;
11312 bool found;
11313 isc_result_t result;
11314 isc_buffer_t b;
11315 dns_fixedname_t fixed;
11316 dns_name_t *name;
11317
11318 /* Skip the command name. */
11319 ptr = next_token(lex, NULL);
11320 if (ptr == NULL)
11321 return (ISC_R_UNEXPECTEDEND);
11322
11323 /* Find the domain name to flush. */
11324 ptr = next_token(lex, NULL);
11325 if (ptr == NULL)
11326 return (ISC_R_UNEXPECTEDEND);
11327
11328 strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
11329 isc_buffer_constinit(&b, target, strlen(target));
11330 isc_buffer_add(&b, strlen(target));
11331 name = dns_fixedname_initname(&fixed);
11332 result = dns_name_fromtext(name, &b, dns_rootname, 0, NULL);
11333 if (result != ISC_R_SUCCESS)
11334 return (result);
11335
11336 /* Look for the view name. */
11337 viewname = next_token(lex, NULL);
11338
11339 result = isc_task_beginexclusive(server->task);
11340 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11341 flushed = true;
11342 found = false;
11343 for (view = ISC_LIST_HEAD(server->viewlist);
11344 view != NULL;
11345 view = ISC_LIST_NEXT(view, link))
11346 {
11347 if (viewname != NULL && strcasecmp(viewname, view->name) != 0)
11348 continue;
11349 found = true;
11350 /*
11351 * It's a little inefficient to try flushing name for all views
11352 * if some of the views share a single cache. But since the
11353 * operation is lightweight we prefer simplicity here.
11354 */
11355 result = dns_view_flushnode(view, name, tree);
11356 if (result != ISC_R_SUCCESS) {
11357 flushed = false;
11358 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11359 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11360 "flushing %s '%s' in cache view '%s' "
11361 "failed: %s",
11362 tree ? "tree" : "name",
11363 target, view->name,
11364 isc_result_totext(result));
11365 }
11366 }
11367 if (flushed && found) {
11368 if (viewname != NULL)
11369 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11370 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11371 "flushing %s '%s' in cache view '%s' "
11372 "succeeded",
11373 tree ? "tree" : "name",
11374 target, viewname);
11375 else
11376 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11377 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11378 "flushing %s '%s' in all cache views "
11379 "succeeded",
11380 tree ? "tree" : "name",
11381 target);
11382 result = ISC_R_SUCCESS;
11383 } else {
11384 if (!found)
11385 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11386 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
11387 "flushing %s '%s' in cache view '%s' "
11388 "failed: view not found",
11389 tree ? "tree" : "name",
11390 target, viewname);
11391 result = ISC_R_FAILURE;
11392 }
11393 isc_task_endexclusive(server->task);
11394 return (result);
11395}
11396
11397isc_result_t
11398named_server_status(named_server_t *server, isc_buffer_t **text) {
11399 isc_result_t result;
11400 unsigned int zonecount, xferrunning, xferdeferred, soaqueries;
11401 unsigned int automatic;
11402 const char *ob = "", *cb = "", *alt = "";
11403 char boottime[ISC_FORMATHTTPTIMESTAMP_SIZE];
11404 char configtime[ISC_FORMATHTTPTIMESTAMP_SIZE];
11405 char line[1024], hostname[256];
11406
11407 if (named_g_server->version_set) {
11408 ob = " (";
11409 cb = ")";
11410 if (named_g_server->version == NULL)
11411 alt = "version.bind/txt/ch disabled";
11412 else
11413 alt = named_g_server->version;
11414 }
11415 zonecount = dns_zonemgr_getcount(server->zonemgr, DNS_ZONESTATE_ANY);
11416 xferrunning = dns_zonemgr_getcount(server->zonemgr,
11417 DNS_ZONESTATE_XFERRUNNING);
11418 xferdeferred = dns_zonemgr_getcount(server->zonemgr,
11419 DNS_ZONESTATE_XFERDEFERRED);
11420 soaqueries = dns_zonemgr_getcount(server->zonemgr,
11421 DNS_ZONESTATE_SOAQUERY);
11422 automatic = dns_zonemgr_getcount(server->zonemgr,
11423 DNS_ZONESTATE_AUTOMATIC);
11424
11425 isc_time_formathttptimestamp(&named_g_boottime, boottime,
11426 sizeof(boottime));
11427 isc_time_formathttptimestamp(&named_g_configtime, configtime,
11428 sizeof(configtime));
11429
11430 snprintf(line, sizeof(line), "version: %s %s%s%s <id:%s>%s%s%s\n",
11431 named_g_product, named_g_version,
11432 (*named_g_description != '\0') ? " " : "",
11433 named_g_description, named_g_srcid, ob, alt, cb);
11434 CHECK(putstr(text, line));
11435
11436 result = named_os_gethostname(hostname, sizeof(hostname));
11437 if (result != ISC_R_SUCCESS)
11438 strlcpy(hostname, "localhost", sizeof(hostname));
11439 snprintf(line, sizeof(line), "running on %s: %s\n",
11440 hostname, named_os_uname());
11441 CHECK(putstr(text, line));
11442
11443 snprintf(line, sizeof(line), "boot time: %s\n", boottime);
11444 CHECK(putstr(text, line));
11445
11446 snprintf(line, sizeof(line), "last configured: %s\n", configtime);
11447 CHECK(putstr(text, line));
11448
11449 if (named_g_chrootdir != NULL) {
11450 snprintf(line, sizeof(line), "configuration file: %s (%s%s)\n",
11451 named_g_conffile, named_g_chrootdir, named_g_conffile);
11452 } else {
11453 snprintf(line, sizeof(line), "configuration file: %s\n",
11454 named_g_conffile);
11455 }
11456 CHECK(putstr(text, line));
11457
11458 snprintf(line, sizeof(line), "CPUs found: %u\n", named_g_cpus_detected);
11459 CHECK(putstr(text, line));
11460
11461 snprintf(line, sizeof(line), "worker threads: %u\n", named_g_cpus);
11462 CHECK(putstr(text, line));
11463
11464 snprintf(line, sizeof(line), "UDP listeners per interface: %u\n",
11465 named_g_udpdisp);
11466 CHECK(putstr(text, line));
11467
11468 snprintf(line, sizeof(line), "number of zones: %u (%u automatic)\n",
11469 zonecount, automatic);
11470 CHECK(putstr(text, line));
11471
11472 snprintf(line, sizeof(line), "debug level: %u\n", named_g_debuglevel);
11473 CHECK(putstr(text, line));
11474
11475 snprintf(line, sizeof(line), "xfers running: %u\n", xferrunning);
11476 CHECK(putstr(text, line));
11477
11478 snprintf(line, sizeof(line), "xfers deferred: %u\n", xferdeferred);
11479 CHECK(putstr(text, line));
11480
11481 snprintf(line, sizeof(line), "soa queries in progress: %u\n",
11482 soaqueries);
11483 CHECK(putstr(text, line));
11484
11485 snprintf(line, sizeof(line), "query logging is %s\n",
11486 ns_server_getoption(server->sctx, NS_SERVER_LOGQUERIES)
11487 ? "ON" : "OFF");
11488 CHECK(putstr(text, line));
11489
11490 snprintf(line, sizeof(line), "recursive clients: %u/%u/%u\n",
11491 isc_quota_getused(&server->sctx->recursionquota),
11492 isc_quota_getsoft(&server->sctx->recursionquota),
11493 isc_quota_getmax(&server->sctx->recursionquota));
11494 CHECK(putstr(text, line));
11495
11496 snprintf(line, sizeof(line), "tcp clients: %u/%u\n",
11497 isc_quota_getused(&server->sctx->tcpquota),
11498 isc_quota_getmax(&server->sctx->tcpquota));
11499 CHECK(putstr(text, line));
11500
11501 if (server->reload_in_progress) {
11502 CHECK(putstr(text, "reload/reconfig in progress"));
11503 }
11504
11505 CHECK(putstr(text, "server is up and running"));
11506 CHECK(putnull(text));
11507
11508 return (ISC_R_SUCCESS);
11509 cleanup:
11510 return (result);
11511}
11512
11513isc_result_t
11514named_server_testgen(isc_lex_t *lex, isc_buffer_t **text) {
11515 isc_result_t result;
11516 char *ptr;
11517 unsigned long count;
11518 unsigned long i;
11519 const unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz0123456789";
11520
11521 /* Skip the command name. */
11522 ptr = next_token(lex, text);
11523 if (ptr == NULL)
11524 return (ISC_R_UNEXPECTEDEND);
11525
11526 ptr = next_token(lex, text);
11527 if (ptr == NULL)
11528 count = 26;
11529 else
11530 count = strtoul(ptr, NULL, 10);
11531
11532 CHECK(isc_buffer_reserve(text, count));
11533 for (i = 0; i < count; i++)
11534 CHECK(putuint8(text, chars[i % (sizeof(chars) - 1)]));
11535
11536 CHECK(putnull(text));
11537
11538 cleanup:
11539 return (result);
11540}
11541
11542static isc_result_t
11543delete_keynames(dns_tsig_keyring_t *ring, char *target,
11544 unsigned int *foundkeys)
11545{
11546 char namestr[DNS_NAME_FORMATSIZE];
11547 isc_result_t result;
11548 dns_rbtnodechain_t chain;
11549 dns_name_t foundname;
11550 dns_fixedname_t fixedorigin;
11551 dns_name_t *origin;
11552 dns_rbtnode_t *node;
11553 dns_tsigkey_t *tkey;
11554
11555 dns_name_init(&foundname, NULL);
11556 origin = dns_fixedname_initname(&fixedorigin);
11557
11558 again:
11559 dns_rbtnodechain_init(&chain, ring->mctx);
11560 result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
11561 origin);
11562 if (result == ISC_R_NOTFOUND) {
11563 dns_rbtnodechain_invalidate(&chain);
11564 return (ISC_R_SUCCESS);
11565 }
11566 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
11567 dns_rbtnodechain_invalidate(&chain);
11568 return (result);
11569 }
11570
11571 for (;;) {
11572 node = NULL;
11573 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
11574 tkey = node->data;
11575
11576 if (tkey != NULL) {
11577 if (!tkey->generated)
11578 goto nextkey;
11579
11580 dns_name_format(&tkey->name, namestr, sizeof(namestr));
11581 if (strcmp(namestr, target) == 0) {
11582 (*foundkeys)++;
11583 dns_rbtnodechain_invalidate(&chain);
11584 (void)dns_rbt_deletename(ring->keys,
11585 &tkey->name,
11586 false);
11587 goto again;
11588 }
11589 }
11590
11591 nextkey:
11592 result = dns_rbtnodechain_next(&chain, &foundname, origin);
11593 if (result == ISC_R_NOMORE)
11594 break;
11595 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
11596 dns_rbtnodechain_invalidate(&chain);
11597 return (result);
11598 }
11599 }
11600
11601 return (ISC_R_SUCCESS);
11602}
11603
11604isc_result_t
11605named_server_tsigdelete(named_server_t *server, isc_lex_t *lex,
11606 isc_buffer_t **text)
11607{
11608 isc_result_t result;
11609 dns_view_t *view;
11610 unsigned int foundkeys = 0;
11611 char *ptr, *viewname;
11612 char target[DNS_NAME_FORMATSIZE];
11613 char fbuf[16];
11614
11615 (void)next_token(lex, text); /* skip command name */
11616
11617 ptr = next_token(lex, text);
11618 if (ptr == NULL)
11619 return (ISC_R_UNEXPECTEDEND);
11620 strlcpy(target, ptr, DNS_NAME_FORMATSIZE);
11621
11622 viewname = next_token(lex, text);
11623
11624 result = isc_task_beginexclusive(server->task);
11625 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11626 for (view = ISC_LIST_HEAD(server->viewlist);
11627 view != NULL;
11628 view = ISC_LIST_NEXT(view, link)) {
11629 if (viewname == NULL || strcmp(view->name, viewname) == 0) {
11630 RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_write);
11631 result = delete_keynames(view->dynamickeys, target,
11632 &foundkeys);
11633 RWUNLOCK(&view->dynamickeys->lock,
11634 isc_rwlocktype_write);
11635 if (result != ISC_R_SUCCESS) {
11636 isc_task_endexclusive(server->task);
11637 return (result);
11638 }
11639 }
11640 }
11641 isc_task_endexclusive(server->task);
11642
11643 snprintf(fbuf, sizeof(fbuf), "%u", foundkeys);
11644
11645 CHECK(putstr(text, fbuf));
11646 CHECK(putstr(text, " tsig keys deleted."));
11647 CHECK(putnull(text));
11648
11649 cleanup:
11650 return (result);
11651}
11652
11653static isc_result_t
11654list_keynames(dns_view_t *view, dns_tsig_keyring_t *ring, isc_buffer_t **text,
11655 unsigned int *foundkeys)
11656{
11657 char namestr[DNS_NAME_FORMATSIZE];
11658 char creatorstr[DNS_NAME_FORMATSIZE];
11659 isc_result_t result;
11660 dns_rbtnodechain_t chain;
11661 dns_name_t foundname;
11662 dns_fixedname_t fixedorigin;
11663 dns_name_t *origin;
11664 dns_rbtnode_t *node;
11665 dns_tsigkey_t *tkey;
11666 const char *viewname;
11667
11668 if (view != NULL)
11669 viewname = view->name;
11670 else
11671 viewname = "(global)";
11672
11673 dns_name_init(&foundname, NULL);
11674 origin = dns_fixedname_initname(&fixedorigin);
11675 dns_rbtnodechain_init(&chain, ring->mctx);
11676 result = dns_rbtnodechain_first(&chain, ring->keys, &foundname,
11677 origin);
11678 if (result == ISC_R_NOTFOUND) {
11679 dns_rbtnodechain_invalidate(&chain);
11680 return (ISC_R_SUCCESS);
11681 }
11682 if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN) {
11683 dns_rbtnodechain_invalidate(&chain);
11684 return (result);
11685 }
11686
11687 for (;;) {
11688 node = NULL;
11689 dns_rbtnodechain_current(&chain, &foundname, origin, &node);
11690 tkey = node->data;
11691
11692 if (tkey != NULL) {
11693 dns_name_format(&tkey->name, namestr, sizeof(namestr));
11694 if (tkey->generated) {
11695 dns_name_format(tkey->creator, creatorstr,
11696 sizeof(creatorstr));
11697 if (*foundkeys != 0)
11698 CHECK(putstr(text, "\n"));
11699 CHECK(putstr(text, "view \""));
11700 CHECK(putstr(text, viewname));
11701 CHECK(putstr(text,
11702 "\"; type \"dynamic\"; key \""));
11703 CHECK(putstr(text, namestr));
11704 CHECK(putstr(text, "\"; creator \""));
11705 CHECK(putstr(text, creatorstr));
11706 CHECK(putstr(text, "\";"));
11707 } else {
11708 if (*foundkeys != 0)
11709 CHECK(putstr(text, "\n"));
11710 CHECK(putstr(text, "view \""));
11711 CHECK(putstr(text, viewname));
11712 CHECK(putstr(text,
11713 "\"; type \"static\"; key \""));
11714 CHECK(putstr(text, namestr));
11715 CHECK(putstr(text, "\";"));
11716 }
11717 (*foundkeys)++;
11718 }
11719 result = dns_rbtnodechain_next(&chain, &foundname, origin);
11720 if (result == ISC_R_NOMORE || result == DNS_R_NEWORIGIN)
11721 break;
11722 }
11723
11724 return (ISC_R_SUCCESS);
11725 cleanup:
11726 dns_rbtnodechain_invalidate(&chain);
11727 return (result);
11728}
11729
11730isc_result_t
11731named_server_tsiglist(named_server_t *server, isc_buffer_t **text) {
11732 isc_result_t result;
11733 dns_view_t *view;
11734 unsigned int foundkeys = 0;
11735
11736 result = isc_task_beginexclusive(server->task);
11737 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11738 for (view = ISC_LIST_HEAD(server->viewlist);
11739 view != NULL;
11740 view = ISC_LIST_NEXT(view, link)) {
11741 RWLOCK(&view->statickeys->lock, isc_rwlocktype_read);
11742 result = list_keynames(view, view->statickeys, text,
11743 &foundkeys);
11744 RWUNLOCK(&view->statickeys->lock, isc_rwlocktype_read);
11745 if (result != ISC_R_SUCCESS) {
11746 isc_task_endexclusive(server->task);
11747 return (result);
11748 }
11749 RWLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
11750 result = list_keynames(view, view->dynamickeys, text,
11751 &foundkeys);
11752 RWUNLOCK(&view->dynamickeys->lock, isc_rwlocktype_read);
11753 if (result != ISC_R_SUCCESS) {
11754 isc_task_endexclusive(server->task);
11755 return (result);
11756 }
11757 }
11758 isc_task_endexclusive(server->task);
11759
11760 if (foundkeys == 0)
11761 CHECK(putstr(text, "no tsig keys found."));
11762
11763 if (isc_buffer_usedlength(*text) > 0)
11764 CHECK(putnull(text));
11765
11766 cleanup:
11767 return (result);
11768}
11769
11770/*
11771 * Act on a "sign" or "loadkeys" command from the command channel.
11772 */
11773isc_result_t
11774named_server_rekey(named_server_t *server, isc_lex_t *lex,
11775 isc_buffer_t **text)
11776{
11777 isc_result_t result;
11778 dns_zone_t *zone = NULL;
11779 dns_zonetype_t type;
11780 uint16_t keyopts;
11781 bool fullsign = false;
11782 char *ptr;
11783
11784 ptr = next_token(lex, text);
11785 if (ptr == NULL)
11786 return (ISC_R_UNEXPECTEDEND);
11787
11788 if (strcasecmp(ptr, NAMED_COMMAND_SIGN) == 0)
11789 fullsign = true;
11790
11791 result = zone_from_args(server, lex, NULL, &zone, NULL,
11792 text, false);
11793 if (result != ISC_R_SUCCESS)
11794 return (result);
11795 if (zone == NULL)
11796 return (ISC_R_UNEXPECTEDEND); /* XXX: or do all zones? */
11797
11798 type = dns_zone_gettype(zone);
11799 if (type != dns_zone_master) {
11800 dns_zone_detach(&zone);
11801 return (DNS_R_NOTMASTER);
11802 }
11803
11804 keyopts = dns_zone_getkeyopts(zone);
11805
11806 /* "rndc loadkeys" requires "auto-dnssec maintain". */
11807 if ((keyopts & DNS_ZONEKEY_ALLOW) == 0)
11808 result = ISC_R_NOPERM;
11809 else if ((keyopts & DNS_ZONEKEY_MAINTAIN) == 0 && !fullsign)
11810 result = ISC_R_NOPERM;
11811 else
11812 dns_zone_rekey(zone, fullsign);
11813
11814 dns_zone_detach(&zone);
11815 return (result);
11816}
11817
11818/*
11819 * Act on a "sync" command from the command channel.
11820*/
11821static isc_result_t
11822synczone(dns_zone_t *zone, void *uap) {
11823 bool cleanup = *(bool *)uap;
11824 isc_result_t result;
11825 dns_zone_t *raw = NULL;
11826 char *journal;
11827
11828 dns_zone_getraw(zone, &raw);
11829 if (raw != NULL) {
11830 synczone(raw, uap);
11831 dns_zone_detach(&raw);
11832 }
11833
11834 result = dns_zone_flush(zone);
11835 if (result != ISC_R_SUCCESS)
11836 cleanup = false;
11837 if (cleanup) {
11838 journal = dns_zone_getjournal(zone);
11839 if (journal != NULL)
11840 (void)isc_file_remove(journal);
11841 }
11842
11843 return (result);
11844}
11845
11846isc_result_t
11847named_server_sync(named_server_t *server, isc_lex_t *lex, isc_buffer_t **text) {
11848 isc_result_t result, tresult;
11849 dns_view_t *view;
11850 dns_zone_t *zone = NULL;
11851 char classstr[DNS_RDATACLASS_FORMATSIZE];
11852 char zonename[DNS_NAME_FORMATSIZE];
11853 const char *vname, *sep, *arg;
11854 bool cleanup = false;
11855
11856 (void) next_token(lex, text);
11857
11858 arg = next_token(lex, text);
11859 if (arg != NULL &&
11860 (strcmp(arg, "-clean") == 0 || strcmp(arg, "-clear") == 0)) {
11861 cleanup = true;
11862 arg = next_token(lex, text);
11863 }
11864
11865 result = zone_from_args(server, lex, arg, &zone, NULL,
11866 text, false);
11867 if (result != ISC_R_SUCCESS)
11868 return (result);
11869
11870 if (zone == NULL) {
11871 result = isc_task_beginexclusive(server->task);
11872 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11873 tresult = ISC_R_SUCCESS;
11874 for (view = ISC_LIST_HEAD(server->viewlist);
11875 view != NULL;
11876 view = ISC_LIST_NEXT(view, link)) {
11877 result = dns_zt_apply(view->zonetable, false,
11878 NULL, synczone, &cleanup);
11879 if (result != ISC_R_SUCCESS &&
11880 tresult == ISC_R_SUCCESS)
11881 tresult = result;
11882 }
11883 isc_task_endexclusive(server->task);
11884 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11885 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11886 "dumping all zones%s: %s",
11887 cleanup ? ", removing journal files" : "",
11888 isc_result_totext(result));
11889 return (tresult);
11890 }
11891
11892 result = isc_task_beginexclusive(server->task);
11893 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11894 result = synczone(zone, &cleanup);
11895 isc_task_endexclusive(server->task);
11896
11897 view = dns_zone_getview(zone);
11898 if (strcmp(view->name, "_default") == 0 ||
11899 strcmp(view->name, "_bind") == 0)
11900 {
11901 vname = "";
11902 sep = "";
11903 } else {
11904 vname = view->name;
11905 sep = " ";
11906 }
11907 dns_rdataclass_format(dns_zone_getclass(zone), classstr,
11908 sizeof(classstr));
11909 dns_name_format(dns_zone_getorigin(zone),
11910 zonename, sizeof(zonename));
11911 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11912 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11913 "sync: dumping zone '%s/%s'%s%s%s: %s",
11914 zonename, classstr, sep, vname,
11915 cleanup ? ", removing journal file" : "",
11916 isc_result_totext(result));
11917 dns_zone_detach(&zone);
11918 return (result);
11919}
11920
11921/*
11922 * Act on a "freeze" or "thaw" command from the command channel.
11923 */
11924isc_result_t
11925named_server_freeze(named_server_t *server, bool freeze,
11926 isc_lex_t *lex, isc_buffer_t **text)
11927{
11928 isc_result_t result, tresult;
11929 dns_zone_t *mayberaw = NULL, *raw = NULL;
11930 dns_zonetype_t type;
11931 char classstr[DNS_RDATACLASS_FORMATSIZE];
11932 char zonename[DNS_NAME_FORMATSIZE];
11933 dns_view_t *view;
11934 const char *vname, *sep;
11935 bool frozen;
11936 const char *msg = NULL;
11937
11938 result = zone_from_args(server, lex, NULL, &mayberaw, NULL,
11939 text, true);
11940 if (result != ISC_R_SUCCESS)
11941 return (result);
11942 if (mayberaw == NULL) {
11943 result = isc_task_beginexclusive(server->task);
11944 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11945 tresult = ISC_R_SUCCESS;
11946 for (view = ISC_LIST_HEAD(server->viewlist);
11947 view != NULL;
11948 view = ISC_LIST_NEXT(view, link)) {
11949 result = dns_view_freezezones(view, freeze);
11950 if (result != ISC_R_SUCCESS &&
11951 tresult == ISC_R_SUCCESS)
11952 tresult = result;
11953 }
11954 isc_task_endexclusive(server->task);
11955 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
11956 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
11957 "%s all zones: %s",
11958 freeze ? "freezing" : "thawing",
11959 isc_result_totext(tresult));
11960 return (tresult);
11961 }
11962 dns_zone_getraw(mayberaw, &raw);
11963 if (raw != NULL) {
11964 dns_zone_detach(&mayberaw);
11965 dns_zone_attach(raw, &mayberaw);
11966 dns_zone_detach(&raw);
11967 }
11968 type = dns_zone_gettype(mayberaw);
11969 if (type != dns_zone_master) {
11970 dns_zone_detach(&mayberaw);
11971 return (DNS_R_NOTMASTER);
11972 }
11973
11974 if (freeze && !dns_zone_isdynamic(mayberaw, true)) {
11975 dns_zone_detach(&mayberaw);
11976 return (DNS_R_NOTDYNAMIC);
11977 }
11978
11979 result = isc_task_beginexclusive(server->task);
11980 RUNTIME_CHECK(result == ISC_R_SUCCESS);
11981 frozen = dns_zone_getupdatedisabled(mayberaw);
11982 if (freeze) {
11983 if (frozen) {
11984 msg = "WARNING: The zone was already frozen.\n"
11985 "Someone else may be editing it or "
11986 "it may still be re-loading.";
11987 result = DNS_R_FROZEN;
11988 }
11989 if (result == ISC_R_SUCCESS) {
11990 result = dns_zone_flush(mayberaw);
11991 if (result != ISC_R_SUCCESS)
11992 msg = "Flushing the zone updates to "
11993 "disk failed.";
11994 }
11995 if (result == ISC_R_SUCCESS)
11996 dns_zone_setupdatedisabled(mayberaw, freeze);
11997 } else {
11998 if (frozen) {
11999 result = dns_zone_loadandthaw(mayberaw);
12000 switch (result) {
12001 case ISC_R_SUCCESS:
12002 case DNS_R_UPTODATE:
12003 msg = "The zone reload and thaw was "
12004 "successful.";
12005 result = ISC_R_SUCCESS;
12006 break;
12007 case DNS_R_CONTINUE:
12008 msg = "A zone reload and thaw was started.\n"
12009 "Check the logs to see the result.";
12010 result = ISC_R_SUCCESS;
12011 break;
12012 }
12013 }
12014 }
12015 isc_task_endexclusive(server->task);
12016
12017 if (msg != NULL) {
12018 (void) putstr(text, msg);
12019 (void) putnull(text);
12020 }
12021
12022 view = dns_zone_getview(mayberaw);
12023 if (strcmp(view->name, "_default") == 0 ||
12024 strcmp(view->name, "_bind") == 0)
12025 {
12026 vname = "";
12027 sep = "";
12028 } else {
12029 vname = view->name;
12030 sep = " ";
12031 }
12032 dns_rdataclass_format(dns_zone_getclass(mayberaw), classstr,
12033 sizeof(classstr));
12034 dns_name_format(dns_zone_getorigin(mayberaw),
12035 zonename, sizeof(zonename));
12036 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12037 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
12038 "%s zone '%s/%s'%s%s: %s",
12039 freeze ? "freezing" : "thawing",
12040 zonename, classstr, sep, vname,
12041 isc_result_totext(result));
12042 dns_zone_detach(&mayberaw);
12043 return (result);
12044}
12045
12046#ifdef HAVE_LIBSCF
12047/*
12048 * This function adds a message for rndc to echo if named
12049 * is managed by smf and is also running chroot.
12050 */
12051isc_result_t
12052named_smf_add_message(isc_buffer_t **text) {
12053 return (putstr(text, "use svcadm(1M) to manage named"));
12054}
12055#endif /* HAVE_LIBSCF */
12056
12057#ifndef HAVE_LMDB
12058
12059/*
12060 * Emit a comment at the top of the nzf file containing the viewname
12061 * Expects the fp to already be open for writing
12062 */
12063#define HEADER1 "# New zone file for view: "
12064#define HEADER2 "\n# This file contains configuration for zones added by\n" \
12065 "# the 'rndc addzone' command. DO NOT EDIT BY HAND.\n"
12066static isc_result_t
12067add_comment(FILE *fp, const char *viewname) {
12068 isc_result_t result;
12069 CHECK(isc_stdio_write(HEADER1, sizeof(HEADER1) - 1, 1, fp, NULL));
12070 CHECK(isc_stdio_write(viewname, strlen(viewname), 1, fp, NULL));
12071 CHECK(isc_stdio_write(HEADER2, sizeof(HEADER2) - 1, 1, fp, NULL));
12072 cleanup:
12073 return (result);
12074}
12075
12076static void
12077dumpzone(void *arg, const char *buf, int len) {
12078 FILE *fp = arg;
12079
12080 (void) isc_stdio_write(buf, len, 1, fp, NULL);
12081}
12082
12083static isc_result_t
12084nzf_append(dns_view_t *view, const cfg_obj_t *zconfig) {
12085 isc_result_t result;
12086 off_t offset;
12087 FILE *fp = NULL;
12088 bool offsetok = false;
12089
12090 LOCK(&view->new_zone_lock);
12091
12092 CHECK(isc_stdio_open(view->new_zone_file, "a", &fp));
12093 CHECK(isc_stdio_seek(fp, 0, SEEK_END));
12094
12095 CHECK(isc_stdio_tell(fp, &offset));
12096 offsetok = true;
12097 if (offset == 0)
12098 CHECK(add_comment(fp, view->name));
12099
12100 CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12101 cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12102 CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12103 CHECK(isc_stdio_flush(fp));
12104 result = isc_stdio_close(fp);
12105 fp = NULL;
12106
12107 cleanup:
12108 if (fp != NULL) {
12109 (void)isc_stdio_close(fp);
12110 if (offsetok) {
12111 isc_result_t result2;
12112
12113 result2 = isc_file_truncate(view->new_zone_file,
12114 offset);
12115 if (result2 != ISC_R_SUCCESS) {
12116 isc_log_write(named_g_lctx,
12117 NAMED_LOGCATEGORY_GENERAL,
12118 NAMED_LOGMODULE_SERVER,
12119 ISC_LOG_ERROR,
12120 "Error truncating NZF file '%s' "
12121 "during rollback from append: "
12122 "%s",
12123 view->new_zone_file,
12124 isc_result_totext(result2));
12125 }
12126 }
12127 }
12128 UNLOCK(&view->new_zone_lock);
12129 return (result);
12130}
12131
12132static isc_result_t
12133nzf_writeconf(const cfg_obj_t *config, dns_view_t *view) {
12134 const cfg_obj_t *zl = NULL;
12135 cfg_list_t *list;
12136 const cfg_listelt_t *elt;
12137
12138 FILE *fp = NULL;
12139 char tmp[1024];
12140 isc_result_t result;
12141
12142 result = isc_file_template(view->new_zone_file, "nzf-XXXXXXXX",
12143 tmp, sizeof(tmp));
12144 if (result == ISC_R_SUCCESS)
12145 result = isc_file_openunique(tmp, &fp);
12146 if (result != ISC_R_SUCCESS)
12147 return (result);
12148
12149 cfg_map_get(config, "zone", &zl);
12150 if (!cfg_obj_islist(zl))
12151 CHECK(ISC_R_FAILURE);
12152
12153 DE_CONST(&zl->value.list, list);
12154
12155 CHECK(add_comment(fp, view->name)); /* force a comment */
12156
12157 for (elt = ISC_LIST_HEAD(*list);
12158 elt != NULL;
12159 elt = ISC_LIST_NEXT(elt, link))
12160 {
12161 const cfg_obj_t *zconfig = cfg_listelt_value(elt);
12162
12163 CHECK(isc_stdio_write("zone ", 5, 1, fp, NULL));
12164 cfg_printx(zconfig, CFG_PRINTER_ONELINE, dumpzone, fp);
12165 CHECK(isc_stdio_write(";\n", 2, 1, fp, NULL));
12166 }
12167
12168 CHECK(isc_stdio_flush(fp));
12169 result = isc_stdio_close(fp);
12170 fp = NULL;
12171 if (result != ISC_R_SUCCESS)
12172 goto cleanup;
12173 CHECK(isc_file_rename(tmp, view->new_zone_file));
12174 return (result);
12175
12176 cleanup:
12177 if (fp != NULL)
12178 (void)isc_stdio_close(fp);
12179 (void)isc_file_remove(tmp);
12180 return (result);
12181}
12182
12183#else /* HAVE_LMDB */
12184
12185static void
12186nzd_setkey(MDB_val *key, dns_name_t *name, char *namebuf, size_t buflen) {
12187 dns_fixedname_t fixed;
12188
12189 dns_fixedname_init(&fixed);
12190 dns_name_downcase(name, dns_fixedname_name(&fixed), NULL);
12191 dns_name_format(dns_fixedname_name(&fixed), namebuf, buflen);
12192
12193 key->mv_data = namebuf;
12194 key->mv_size = strlen(namebuf);
12195}
12196
12197static void
12198dumpzone(void *arg, const char *buf, int len) {
12199 ns_dzarg_t *dzarg = arg;
12200 isc_result_t result;
12201
12202 REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
12203
12204 result = putmem(dzarg->text, buf, len);
12205 if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
12206 dzarg->result = result;
12207 }
12208}
12209
12210static isc_result_t
12211nzd_save(MDB_txn **txnp, MDB_dbi dbi, dns_zone_t *zone,
12212 const cfg_obj_t *zconfig)
12213{
12214 isc_result_t result;
12215 int status;
12216 dns_view_t *view;
12217 bool commit = false;
12218 isc_buffer_t *text = NULL;
12219 char namebuf[1024];
12220 MDB_val key, data;
12221 ns_dzarg_t dzarg;
12222
12223 view = dns_zone_getview(zone);
12224
12225 nzd_setkey(&key, dns_zone_getorigin(zone), namebuf, sizeof(namebuf));
12226
12227 LOCK(&view->new_zone_lock);
12228
12229 if (zconfig == NULL) {
12230 /* We're deleting the zone from the database */
12231 status = mdb_del(*txnp, dbi, &key, NULL);
12232 if (status != MDB_SUCCESS && status != MDB_NOTFOUND) {
12233 isc_log_write(named_g_lctx,
12234 NAMED_LOGCATEGORY_GENERAL,
12235 NAMED_LOGMODULE_SERVER,
12236 ISC_LOG_ERROR,
12237 "Error deleting zone %s "
12238 "from NZD database: %s",
12239 namebuf, mdb_strerror(status));
12240 result = ISC_R_FAILURE;
12241 goto cleanup;
12242 } else if (status != MDB_NOTFOUND) {
12243 commit = true;
12244 }
12245 } else {
12246 /* We're creating or overwriting the zone */
12247 const cfg_obj_t *zoptions;
12248
12249 result = isc_buffer_allocate(view->mctx, &text, 256);
12250 if (result != ISC_R_SUCCESS) {
12251 isc_log_write(named_g_lctx,
12252 NAMED_LOGCATEGORY_GENERAL,
12253 NAMED_LOGMODULE_SERVER,
12254 ISC_LOG_ERROR,
12255 "Unable to allocate buffer in "
12256 "nzd_save(): %s",
12257 isc_result_totext(result));
12258 goto cleanup;
12259 }
12260
12261 zoptions = cfg_tuple_get(zconfig, "options");
12262 if (zoptions == NULL) {
12263 isc_log_write(named_g_lctx,
12264 NAMED_LOGCATEGORY_GENERAL,
12265 NAMED_LOGMODULE_SERVER,
12266 ISC_LOG_ERROR,
12267 "Unable to get options from config in "
12268 "nzd_save()");
12269 result = ISC_R_FAILURE;
12270 goto cleanup;
12271 }
12272
12273 dzarg.magic = DZARG_MAGIC;
12274 dzarg.text = &text;
12275 dzarg.result = ISC_R_SUCCESS;
12276 cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
12277 if (dzarg.result != ISC_R_SUCCESS) {
12278 isc_log_write(named_g_lctx,
12279 NAMED_LOGCATEGORY_GENERAL,
12280 NAMED_LOGMODULE_SERVER,
12281 ISC_LOG_ERROR,
12282 "Error writing zone config to "
12283 "buffer in nzd_save(): %s",
12284 isc_result_totext(result));
12285 result = dzarg.result;
12286 goto cleanup;
12287 }
12288
12289 data.mv_data = isc_buffer_base(text);
12290 data.mv_size = isc_buffer_usedlength(text);
12291
12292 status = mdb_put(*txnp, dbi, &key, &data, 0);
12293 if (status != MDB_SUCCESS) {
12294 isc_log_write(named_g_lctx,
12295 NAMED_LOGCATEGORY_GENERAL,
12296 NAMED_LOGMODULE_SERVER,
12297 ISC_LOG_ERROR,
12298 "Error inserting zone in "
12299 "NZD database: %s",
12300 mdb_strerror(status));
12301 result = ISC_R_FAILURE;
12302 goto cleanup;
12303 }
12304
12305 commit = true;
12306 }
12307
12308 result = ISC_R_SUCCESS;
12309
12310 cleanup:
12311 if (!commit || result != ISC_R_SUCCESS) {
12312 (void) mdb_txn_abort(*txnp);
12313 } else {
12314 status = mdb_txn_commit(*txnp);
12315 if (status != MDB_SUCCESS) {
12316 isc_log_write(named_g_lctx,
12317 NAMED_LOGCATEGORY_GENERAL,
12318 NAMED_LOGMODULE_SERVER,
12319 ISC_LOG_ERROR,
12320 "Error committing "
12321 "NZD database: %s",
12322 mdb_strerror(status));
12323 result = ISC_R_FAILURE;
12324 }
12325 }
12326 *txnp = NULL;
12327
12328 UNLOCK(&view->new_zone_lock);
12329
12330 if (text != NULL) {
12331 isc_buffer_free(&text);
12332 }
12333
12334 return (result);
12335}
12336
12337static isc_result_t
12338nzd_writable(dns_view_t *view) {
12339 isc_result_t result = ISC_R_SUCCESS;
12340 int status;
12341 MDB_dbi dbi;
12342 MDB_txn *txn = NULL;
12343
12344 REQUIRE(view != NULL);
12345
12346 status = mdb_txn_begin((MDB_env *) view->new_zone_dbenv, 0, 0, &txn);
12347 if (status != MDB_SUCCESS) {
12348 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12349 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12350 "mdb_txn_begin: %s",
12351 mdb_strerror(status));
12352 return (ISC_R_FAILURE);
12353 }
12354
12355 status = mdb_dbi_open(txn, NULL, 0, &dbi);
12356 if (status != MDB_SUCCESS) {
12357 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
12358 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
12359 "mdb_dbi_open: %s",
12360 mdb_strerror(status));
12361 result = ISC_R_FAILURE;
12362 }
12363
12364 mdb_txn_abort(txn);
12365 return (result);
12366}
12367
12368static isc_result_t
12369nzd_open(dns_view_t *view, unsigned int flags, MDB_txn **txnp, MDB_dbi *dbi) {
12370 int status;
12371 MDB_txn *txn = NULL;
12372
12373 REQUIRE(view != NULL);
12374 REQUIRE(txnp != NULL && *txnp == NULL);
12375 REQUIRE(dbi != NULL);
12376
12377 status = mdb_txn_begin((MDB_env *) view->new_zone_dbenv, 0,
12378 flags, &txn);
12379 if (status != MDB_SUCCESS) {
12380 isc_log_write(named_g_lctx,
12381 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12382 ISC_LOG_WARNING, "mdb_txn_begin: %s",
12383 mdb_strerror(status));
12384 goto cleanup;
12385 }
12386
12387 status = mdb_dbi_open(txn, NULL, 0, dbi);
12388 if (status != MDB_SUCCESS) {
12389 isc_log_write(named_g_lctx,
12390 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12391 ISC_LOG_WARNING, "mdb_dbi_open: %s",
12392 mdb_strerror(status));
12393 goto cleanup;
12394 }
12395
12396 *txnp = txn;
12397
12398 cleanup:
12399 if (status != MDB_SUCCESS) {
12400 if (txn != NULL) {
12401 mdb_txn_abort(txn);
12402 }
12403 return (ISC_R_FAILURE);
12404 }
12405
12406 return (ISC_R_SUCCESS);
12407}
12408
12409/*
12410 * nzd_env_close() and nzd_env_reopen are a kluge to address the
12411 * problem of an NZD file possibly being created before we drop
12412 * root privileges.
12413 */
12414static void
12415nzd_env_close(dns_view_t *view) {
12416 const char *dbpath = NULL;
12417 char dbpath_copy[PATH_MAX];
12418 char lockpath[PATH_MAX];
12419 int status, ret;
12420
12421 if (view->new_zone_dbenv == NULL) {
12422 return;
12423 }
12424
12425 status = mdb_env_get_path(view->new_zone_dbenv, &dbpath);
12426 INSIST(status == MDB_SUCCESS);
12427 snprintf(lockpath, sizeof(lockpath), "%s-lock", dbpath);
12428 strlcpy(dbpath_copy, dbpath, sizeof(dbpath_copy));
12429 mdb_env_close((MDB_env *) view->new_zone_dbenv);
12430
12431 /*
12432 * Database files must be owned by the eventual user, not by root.
12433 */
12434 ret = chown(dbpath_copy, ns_os_uid(), -1);
12435 UNUSED(ret);
12436
12437 /*
12438 * Some platforms need the lockfile not to exist when we reopen the
12439 * environment.
12440 */
12441 (void) isc_file_remove(lockpath);
12442
12443 view->new_zone_dbenv = NULL;
12444}
12445
12446static isc_result_t
12447nzd_env_reopen(dns_view_t *view) {
12448 isc_result_t result;
12449 MDB_env *env = NULL;
12450 int status;
12451
12452 if (view->new_zone_db == NULL) {
12453 return (ISC_R_SUCCESS);
12454 }
12455
12456 nzd_env_close(view);
12457
12458 status = mdb_env_create(&env);
12459 if (status != MDB_SUCCESS) {
12460 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12461 ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12462 "mdb_env_create failed: %s",
12463 mdb_strerror(status));
12464 CHECK(ISC_R_FAILURE);
12465 }
12466
12467 if (view->new_zone_mapsize != 0ULL) {
12468 status = mdb_env_set_mapsize(env, view->new_zone_mapsize);
12469 if (status != MDB_SUCCESS) {
12470 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12471 ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12472 "mdb_env_set_mapsize failed: %s",
12473 mdb_strerror(status));
12474 CHECK(ISC_R_FAILURE);
12475 }
12476 }
12477
12478 status = mdb_env_open(env, view->new_zone_db, DNS_LMDB_FLAGS, 0600);
12479 if (status != MDB_SUCCESS) {
12480 isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
12481 ISC_LOGMODULE_OTHER, ISC_LOG_ERROR,
12482 "mdb_env_open of '%s' failed: %s",
12483 view->new_zone_db, mdb_strerror(status));
12484 CHECK(ISC_R_FAILURE);
12485 }
12486
12487 view->new_zone_dbenv = env;
12488 env = NULL;
12489 result = ISC_R_SUCCESS;
12490
12491 cleanup:
12492 if (env != NULL) {
12493 mdb_env_close(env);
12494 }
12495 return (result);
12496}
12497
12498static isc_result_t
12499nzd_close(MDB_txn **txnp, bool commit) {
12500 isc_result_t result = ISC_R_SUCCESS;
12501 int status;
12502
12503 REQUIRE(txnp != NULL);
12504
12505 if (*txnp != NULL) {
12506 if (commit) {
12507 status = mdb_txn_commit(*txnp);
12508 if (status != MDB_SUCCESS) {
12509 result = ISC_R_FAILURE;
12510 }
12511 } else {
12512 mdb_txn_abort(*txnp);
12513 }
12514 *txnp = NULL;
12515 }
12516
12517 return (result);
12518}
12519
12520static isc_result_t
12521nzd_count(dns_view_t *view, int *countp) {
12522 isc_result_t result;
12523 int status;
12524 MDB_txn *txn = NULL;
12525 MDB_dbi dbi;
12526 MDB_stat statbuf;
12527
12528 REQUIRE(countp != NULL);
12529
12530 result = nzd_open(view, MDB_RDONLY, &txn, &dbi);
12531 if (result != ISC_R_SUCCESS) {
12532 goto cleanup;
12533 }
12534
12535 status = mdb_stat(txn, dbi, &statbuf);
12536 if (status != MDB_SUCCESS) {
12537 isc_log_write(named_g_lctx,
12538 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12539 ISC_LOG_WARNING, "mdb_stat: %s",
12540 mdb_strerror(status));
12541 result = ISC_R_FAILURE;
12542 goto cleanup;
12543 }
12544
12545 *countp = statbuf.ms_entries;
12546
12547 cleanup:
12548 (void) nzd_close(&txn, false);
12549
12550 return (result);
12551}
12552
12553static isc_result_t
12554migrate_nzf(dns_view_t *view) {
12555 isc_result_t result;
12556 cfg_obj_t *nzf_config = NULL;
12557 int status, n;
12558 isc_buffer_t *text = NULL;
12559 bool commit = false;
12560 const cfg_obj_t *zonelist;
12561 const cfg_listelt_t *element;
12562 char tempname[PATH_MAX];
12563 MDB_txn *txn = NULL;
12564 MDB_dbi dbi;
12565 MDB_val key, data;
12566 ns_dzarg_t dzarg;
12567
12568 /*
12569 * If NZF file doesn't exist, or NZD DB exists and already
12570 * has data, return without attempting migration.
12571 */
12572 if (!isc_file_exists(view->new_zone_file)) {
12573 result = ISC_R_SUCCESS;
12574 goto cleanup;
12575 }
12576
12577 result = nzd_count(view, &n);
12578 if (result == ISC_R_SUCCESS && n > 0) {
12579 result = ISC_R_SUCCESS;
12580 goto cleanup;
12581 }
12582
12583 isc_log_write(named_g_lctx,
12584 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12585 ISC_LOG_INFO,
12586 "Migrating zones from NZF file '%s' to "
12587 "NZD database '%s'",
12588 view->new_zone_file, view->new_zone_db);
12589 /*
12590 * Instead of blindly copying lines, we parse the NZF file using
12591 * the configuration parser, because it validates it against the
12592 * config type, giving us a guarantee that valid configuration
12593 * will be written to DB.
12594 */
12595 cfg_parser_reset(named_g_addparser);
12596 result = cfg_parse_file(named_g_addparser, view->new_zone_file,
12597 &cfg_type_addzoneconf, &nzf_config);
12598 if (result != ISC_R_SUCCESS) {
12599 isc_log_write(named_g_lctx,
12600 NAMED_LOGCATEGORY_GENERAL, NAMED_LOGMODULE_SERVER,
12601 ISC_LOG_ERROR,
12602 "Error parsing NZF file '%s': %s",
12603 view->new_zone_file,
12604 isc_result_totext(result));
12605 goto cleanup;
12606 }
12607
12608 zonelist = NULL;
12609 CHECK(cfg_map_get(nzf_config, "zone", &zonelist));
12610 if (!cfg_obj_islist(zonelist)) {
12611 CHECK(ISC_R_FAILURE);
12612 }
12613
12614 CHECK(nzd_open(view, 0, &txn, &dbi));
12615
12616 CHECK(isc_buffer_allocate(view->mctx, &text, 256));
12617
12618 for (element = cfg_list_first(zonelist);
12619 element != NULL;
12620 element = cfg_list_next(element))
12621 {
12622 const cfg_obj_t *zconfig;
12623 const cfg_obj_t *zoptions;
12624 char zname[DNS_NAME_FORMATSIZE];
12625 dns_fixedname_t fname;
12626 dns_name_t *name;
12627 const char *origin;
12628 isc_buffer_t b;
12629
12630 zconfig = cfg_listelt_value(element);
12631
12632 origin = cfg_obj_asstring(cfg_tuple_get(zconfig, "name"));
12633 if (origin == NULL) {
12634 result = ISC_R_FAILURE;
12635 goto cleanup;
12636 }
12637
12638 /* Normalize zone name */
12639 isc_buffer_constinit(&b, origin, strlen(origin));
12640 isc_buffer_add(&b, strlen(origin));
12641 name = dns_fixedname_initname(&fname);
12642 CHECK(dns_name_fromtext(name, &b, dns_rootname,
12643 DNS_NAME_DOWNCASE, NULL));
12644 dns_name_format(name, zname, sizeof(zname));
12645
12646 key.mv_data = zname;
12647 key.mv_size = strlen(zname);
12648
12649 zoptions = cfg_tuple_get(zconfig, "options");
12650 if (zoptions == NULL) {
12651 result = ISC_R_FAILURE;
12652 goto cleanup;
12653 }
12654
12655 isc_buffer_clear(text);
12656 dzarg.magic = DZARG_MAGIC;
12657 dzarg.text = &text;
12658 dzarg.result = ISC_R_SUCCESS;
12659 cfg_printx(zoptions, CFG_PRINTER_ONELINE, dumpzone, &dzarg);
12660 if (dzarg.result != ISC_R_SUCCESS) {
12661 isc_log_write(named_g_lctx,
12662 NAMED_LOGCATEGORY_GENERAL,
12663 NAMED_LOGMODULE_SERVER,
12664 ISC_LOG_ERROR,
12665 "Error writing zone config to "
12666 "buffer in migrate_nzf(): %s",
12667 isc_result_totext(result));
12668 result = dzarg.result;
12669 goto cleanup;
12670 }
12671
12672 data.mv_data = isc_buffer_base(text);
12673 data.mv_size = isc_buffer_usedlength(text);
12674
12675 status = mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE);
12676 if (status != MDB_SUCCESS) {
12677 isc_log_write(named_g_lctx,
12678 NAMED_LOGCATEGORY_GENERAL,
12679 NAMED_LOGMODULE_SERVER,
12680 ISC_LOG_ERROR,
12681 "Error inserting zone in "
12682 "NZD database: %s",
12683 mdb_strerror(status));
12684 result = ISC_R_FAILURE;
12685 goto cleanup;
12686 }
12687
12688 commit = true;
12689 }
12690
12691 result = ISC_R_SUCCESS;
12692
12693 /*
12694 * Leaving the NZF file in place is harmless as we won't use it
12695 * if an NZD database is found for the view. But we rename NZF file
12696 * to a backup name here.
12697 */
12698 strlcpy(tempname, view->new_zone_file, sizeof(tempname));
12699 if (strlen(tempname) < sizeof(tempname) - 1) {
12700 strlcat(tempname, "~", sizeof(tempname));
12701 isc_file_rename(view->new_zone_file, tempname);
12702 }
12703
12704 cleanup:
12705 if (result != ISC_R_SUCCESS) {
12706 (void) nzd_close(&txn, false);
12707 } else {
12708 result = nzd_close(&txn, commit);
12709 }
12710
12711 if (text != NULL) {
12712 isc_buffer_free(&text);
12713 }
12714
12715 if (nzf_config != NULL) {
12716 cfg_obj_destroy(named_g_addparser, &nzf_config);
12717 }
12718
12719 return (result);
12720}
12721
12722#endif /* HAVE_LMDB */
12723
12724static isc_result_t
12725newzone_parse(named_server_t *server, char *command, dns_view_t **viewp,
12726 cfg_obj_t **zoneconfp, const cfg_obj_t **zoneobjp,
12727 bool *redirectp, isc_buffer_t **text)
12728{
12729 isc_result_t result;
12730 isc_buffer_t argbuf;
12731 bool redirect = false;
12732 cfg_obj_t *zoneconf = NULL;
12733 const cfg_obj_t *zlist = NULL;
12734 const cfg_obj_t *zoneobj = NULL;
12735 const cfg_obj_t *zoptions = NULL;
12736 const cfg_obj_t *obj = NULL;
12737 const char *viewname = NULL;
12738 dns_rdataclass_t rdclass;
12739 dns_view_t *view = NULL;
12740 const char *bn = NULL;
12741
12742 REQUIRE(viewp != NULL && *viewp == NULL);
12743 REQUIRE(zoneobjp != NULL && *zoneobjp == NULL);
12744 REQUIRE(zoneconfp != NULL && *zoneconfp == NULL);
12745 REQUIRE(redirectp != NULL);
12746
12747 /* Try to parse the argument string */
12748 isc_buffer_init(&argbuf, command, (unsigned int) strlen(command));
12749 isc_buffer_add(&argbuf, strlen(command));
12750
12751 if (strncasecmp(command, "add", 3) == 0) {
12752 bn = "addzone";
12753 } else if (strncasecmp(command, "mod", 3) == 0) {
12754 bn = "modzone";
12755 } else {
12756 INSIST(0);
12757 ISC_UNREACHABLE();
12758 }
12759
12760 /*
12761 * Convert the "addzone" or "modzone" to just "zone", for
12762 * the benefit of the parser
12763 */
12764 isc_buffer_forward(&argbuf, 3);
12765
12766 cfg_parser_reset(named_g_addparser);
12767 CHECK(cfg_parse_buffer(named_g_addparser, &argbuf, bn, 0,
12768 &cfg_type_addzoneconf, 0, &zoneconf));
12769 CHECK(cfg_map_get(zoneconf, "zone", &zlist));
12770 if (!cfg_obj_islist(zlist))
12771 CHECK(ISC_R_FAILURE);
12772
12773 /* For now we only support adding one zone at a time */
12774 zoneobj = cfg_listelt_value(cfg_list_first(zlist));
12775
12776 /* Check the zone type for ones that are not supported by addzone. */
12777 zoptions = cfg_tuple_get(zoneobj, "options");
12778
12779 obj = NULL;
12780 (void)cfg_map_get(zoptions, "type", &obj);
12781 if (obj == NULL) {
12782 (void) cfg_map_get(zoptions, "in-view", &obj);
12783 if (obj != NULL) {
12784 (void) putstr(text,
12785 "'in-view' zones not supported by ");
12786 (void) putstr(text, bn);
12787 } else
12788 (void) putstr(text, "zone type not specified");
12789 CHECK(ISC_R_FAILURE);
12790 }
12791
12792 if (strcasecmp(cfg_obj_asstring(obj), "hint") == 0 ||
12793 strcasecmp(cfg_obj_asstring(obj), "forward") == 0 ||
12794 strcasecmp(cfg_obj_asstring(obj), "delegation-only") == 0)
12795 {
12796 (void) putstr(text, "'");
12797 (void) putstr(text, cfg_obj_asstring(obj));
12798 (void) putstr(text, "' zones not supported by ");
12799 (void) putstr(text, bn);
12800 CHECK(ISC_R_FAILURE);
12801 }
12802
12803 if (strcasecmp(cfg_obj_asstring(obj), "redirect") == 0)
12804 redirect = true;
12805
12806 /* Make sense of optional class argument */
12807 obj = cfg_tuple_get(zoneobj, "class");
12808 CHECK(named_config_getclass(obj, dns_rdataclass_in, &rdclass));
12809
12810 /* Make sense of optional view argument */
12811 obj = cfg_tuple_get(zoneobj, "view");
12812 if (obj && cfg_obj_isstring(obj))
12813 viewname = cfg_obj_asstring(obj);
12814 if (viewname == NULL || *viewname == '\0')
12815 viewname = "_default";
12816 result = dns_viewlist_find(&server->viewlist, viewname, rdclass,
12817 &view);
12818 if (result == ISC_R_NOTFOUND) {
12819 (void) putstr(text, "no matching view found for '");
12820 (void) putstr(text, viewname);
12821 (void) putstr(text, "'");
12822 goto cleanup;
12823 } else if (result != ISC_R_SUCCESS) {
12824 goto cleanup;
12825 }
12826
12827 *viewp = view;
12828 *zoneobjp = zoneobj;
12829 *zoneconfp = zoneconf;
12830 *redirectp = redirect;
12831
12832 return (ISC_R_SUCCESS);
12833
12834 cleanup:
12835 if (zoneconf != NULL)
12836 cfg_obj_destroy(named_g_addparser, &zoneconf);
12837 if (view != NULL)
12838 dns_view_detach(&view);
12839
12840 return (result);
12841}
12842
12843static isc_result_t
12844delete_zoneconf(dns_view_t *view, cfg_parser_t *pctx,
12845 const cfg_obj_t *config, const dns_name_t *zname,
12846 nzfwriter_t nzfwriter)
12847{
12848 isc_result_t result = ISC_R_NOTFOUND;
12849 const cfg_listelt_t *elt = NULL;
12850 const cfg_obj_t *zl = NULL;
12851 cfg_list_t *list;
12852 dns_fixedname_t myfixed;
12853 dns_name_t *myname;
12854
12855 REQUIRE(view != NULL);
12856 REQUIRE(pctx != NULL);
12857 REQUIRE(config != NULL);
12858 REQUIRE(zname != NULL);
12859
12860 LOCK(&view->new_zone_lock);
12861
12862 cfg_map_get(config, "zone", &zl);
12863
12864 if (!cfg_obj_islist(zl))
12865 CHECK(ISC_R_FAILURE);
12866
12867 DE_CONST(&zl->value.list, list);
12868
12869 myname = dns_fixedname_initname(&myfixed);
12870
12871 for (elt = ISC_LIST_HEAD(*list);
12872 elt != NULL;
12873 elt = ISC_LIST_NEXT(elt, link))
12874 {
12875 const cfg_obj_t *zconf = cfg_listelt_value(elt);
12876 const char *zn;
12877 cfg_listelt_t *e;
12878
12879 zn = cfg_obj_asstring(cfg_tuple_get(zconf, "name"));
12880 result = dns_name_fromstring(myname, zn, 0, NULL);
12881 if (result != ISC_R_SUCCESS ||
12882 !dns_name_equal(zname, myname))
12883 continue;
12884
12885 DE_CONST(elt, e);
12886 ISC_LIST_UNLINK(*list, e, link);
12887 cfg_obj_destroy(pctx, &e->obj);
12888 isc_mem_put(pctx->mctx, e, sizeof(*e));
12889 result = ISC_R_SUCCESS;
12890 break;
12891 }
12892
12893 /*
12894 * Write config to NZF file if appropriate
12895 */
12896 if (nzfwriter != NULL && view->new_zone_file != NULL)
12897 result = nzfwriter(config, view);
12898
12899 cleanup:
12900 UNLOCK(&view->new_zone_lock);
12901 return (result);
12902}
12903
12904static isc_result_t
12905do_addzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
12906 dns_name_t *name, cfg_obj_t *zoneconf, const cfg_obj_t *zoneobj,
12907 bool redirect, isc_buffer_t **text)
12908{
12909 isc_result_t result, tresult;
12910 dns_zone_t *zone = NULL;
12911#ifndef HAVE_LMDB
12912 FILE *fp = NULL;
12913 bool cleanup_config = false;
12914#else /* HAVE_LMDB */
12915 MDB_txn *txn = NULL;
12916 MDB_dbi dbi;
12917
12918 UNUSED(zoneconf);
12919#endif /* HAVE_LMDB */
12920
12921 /* Zone shouldn't already exist */
12922 if (redirect) {
12923 result = (view->redirect != NULL) ? ISC_R_SUCCESS :
12924 ISC_R_NOTFOUND;
12925 } else
12926 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
12927 if (result == ISC_R_SUCCESS) {
12928 result = ISC_R_EXISTS;
12929 goto cleanup;
12930 } else if (result == DNS_R_PARTIALMATCH) {
12931 /* Create our sub-zone anyway */
12932 dns_zone_detach(&zone);
12933 zone = NULL;
12934 } else if (result != ISC_R_NOTFOUND)
12935 goto cleanup;
12936
12937#ifndef HAVE_LMDB
12938 /*
12939 * Make sure we can open the configuration save file
12940 */
12941 result = isc_stdio_open(view->new_zone_file, "a", &fp);
12942 if (result != ISC_R_SUCCESS) {
12943 TCHECK(putstr(text, "unable to create '"));
12944 TCHECK(putstr(text, view->new_zone_file));
12945 TCHECK(putstr(text, "': "));
12946 TCHECK(putstr(text, isc_result_totext(result)));
12947 goto cleanup;
12948 }
12949
12950 (void)isc_stdio_close(fp);
12951 fp = NULL;
12952#else /* HAVE_LMDB */
12953 /* Make sure we can open the NZD database */
12954 result = nzd_writable(view);
12955 if (result != ISC_R_SUCCESS) {
12956 TCHECK(putstr(text, "unable to open NZD database for '"));
12957 TCHECK(putstr(text, view->new_zone_db));
12958 TCHECK(putstr(text, "'"));
12959 result = ISC_R_FAILURE;
12960 goto cleanup;
12961 }
12962#endif /* HAVE_LMDB */
12963
12964 result = isc_task_beginexclusive(server->task);
12965 RUNTIME_CHECK(result == ISC_R_SUCCESS);
12966
12967 /* Mark view unfrozen and configure zone */
12968 dns_view_thaw(view);
12969 result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
12970 server->mctx, view, &server->viewlist,
12971 cfg->actx, true, false, false);
12972 dns_view_freeze(view);
12973
12974 isc_task_endexclusive(server->task);
12975
12976 if (result != ISC_R_SUCCESS) {
12977 TCHECK(putstr(text, "configure_zone failed: "));
12978 TCHECK(putstr(text, isc_result_totext(result)));
12979 goto cleanup;
12980 }
12981
12982 /* Is it there yet? */
12983 if (redirect) {
12984 if (view->redirect == NULL)
12985 CHECK(ISC_R_NOTFOUND);
12986 dns_zone_attach(view->redirect, &zone);
12987 } else {
12988 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
12989 if (result != ISC_R_SUCCESS) {
12990 isc_log_write(named_g_lctx,
12991 NAMED_LOGCATEGORY_GENERAL,
12992 NAMED_LOGMODULE_SERVER,
12993 ISC_LOG_ERROR,
12994 "added new zone was not found: %s",
12995 isc_result_totext(result));
12996 goto cleanup;
12997 }
12998 }
12999
13000#ifndef HAVE_LMDB
13001 /*
13002 * If there wasn't a previous newzone config, just save the one
13003 * we've created. If there was a previous one, merge the new
13004 * zone into it.
13005 */
13006 if (cfg->nzf_config == NULL) {
13007 cfg_obj_attach(zoneconf, &cfg->nzf_config);
13008 } else {
13009 cfg_obj_t *z;
13010 DE_CONST(zoneobj, z);
13011 CHECK(cfg_parser_mapadd(cfg->add_parser,
13012 cfg->nzf_config, z, "zone"));
13013 }
13014 cleanup_config = true;
13015#endif /* HAVE_LMDB */
13016
13017 /*
13018 * Load the zone from the master file. If this fails, we'll
13019 * need to undo the configuration we've done already.
13020 */
13021 result = dns_zone_load(zone, true);
13022 if (result != ISC_R_SUCCESS) {
13023 dns_db_t *dbp = NULL;
13024
13025 TCHECK(putstr(text, "dns_zone_loadnew failed: "));
13026 TCHECK(putstr(text, isc_result_totext(result)));
13027
13028 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13029 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13030 "addzone failed; reverting.");
13031
13032 /* If the zone loaded partially, unload it */
13033 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13034 dns_db_detach(&dbp);
13035 dns_zone_unload(zone);
13036 }
13037
13038 /* Remove the zone from the zone table */
13039 dns_zt_unmount(view->zonetable, zone);
13040 goto cleanup;
13041 }
13042
13043 /* Flag the zone as having been added at runtime */
13044 dns_zone_setadded(zone, true);
13045
13046#ifdef HAVE_LMDB
13047 /* Save the new zone configuration into the NZD */
13048 CHECK(nzd_open(view, 0, &txn, &dbi));
13049 CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13050#else
13051 /* Append the zone configuration to the NZF */
13052 result = nzf_append(view, zoneobj);
13053#endif /* HAVE_LMDB */
13054
13055 cleanup:
13056
13057#ifndef HAVE_LMDB
13058 if (fp != NULL)
13059 (void)isc_stdio_close(fp);
13060 if (result != ISC_R_SUCCESS && cleanup_config) {
13061 tresult = delete_zoneconf(view, cfg->add_parser,
13062 cfg->nzf_config, name,
13063 NULL);
13064 RUNTIME_CHECK(tresult == ISC_R_SUCCESS);
13065 }
13066#else /* HAVE_LMDB */
13067 if (txn != NULL)
13068 (void) nzd_close(&txn, false);
13069#endif /* HAVE_LMDB */
13070
13071 if (zone != NULL)
13072 dns_zone_detach(&zone);
13073
13074 return (result);
13075}
13076
13077static isc_result_t
13078do_modzone(named_server_t *server, ns_cfgctx_t *cfg, dns_view_t *view,
13079 dns_name_t *name, const char *zname, const cfg_obj_t *zoneobj,
13080 bool redirect, isc_buffer_t **text)
13081{
13082 isc_result_t result, tresult;
13083 dns_zone_t *zone = NULL;
13084 bool added;
13085 bool exclusive = false;
13086#ifndef HAVE_LMDB
13087 FILE *fp = NULL;
13088 cfg_obj_t *z;
13089#else /* HAVE_LMDB */
13090 MDB_txn *txn = NULL;
13091 MDB_dbi dbi;
13092#endif /* HAVE_LMDB */
13093
13094 /* Zone must already exist */
13095 if (redirect) {
13096 if (view->redirect != NULL) {
13097 dns_zone_attach(view->redirect, &zone);
13098 result = ISC_R_SUCCESS;
13099 } else
13100 result = ISC_R_NOTFOUND;
13101 } else
13102 result = dns_zt_find(view->zonetable, name, 0, NULL, &zone);
13103 if (result != ISC_R_SUCCESS)
13104 goto cleanup;
13105
13106 added = dns_zone_getadded(zone);
13107 dns_zone_detach(&zone);
13108
13109#ifndef HAVE_LMDB
13110 cfg = (ns_cfgctx_t *) view->new_zone_config;
13111 if (cfg == NULL) {
13112 TCHECK(putstr(text, "new zone config is not set"));
13113 CHECK(ISC_R_FAILURE);
13114 }
13115#endif
13116
13117 result = isc_task_beginexclusive(server->task);
13118 RUNTIME_CHECK(result == ISC_R_SUCCESS);
13119 exclusive = true;
13120
13121#ifndef HAVE_LMDB
13122 /* Make sure we can open the configuration save file */
13123 result = isc_stdio_open(view->new_zone_file, "a", &fp);
13124 if (result != ISC_R_SUCCESS) {
13125 TCHECK(putstr(text, "unable to open '"));
13126 TCHECK(putstr(text, view->new_zone_file));
13127 TCHECK(putstr(text, "': "));
13128 TCHECK(putstr(text, isc_result_totext(result)));
13129 goto cleanup;
13130 }
13131 (void)isc_stdio_close(fp);
13132 fp = NULL;
13133#else /* HAVE_LMDB */
13134 /* Make sure we can open the NZD database */
13135 result = nzd_writable(view);
13136 if (result != ISC_R_SUCCESS) {
13137 TCHECK(putstr(text, "unable to open NZD database for '"));
13138 TCHECK(putstr(text, view->new_zone_db));
13139 TCHECK(putstr(text, "'"));
13140 result = ISC_R_FAILURE;
13141 goto cleanup;
13142 }
13143#endif /* HAVE_LMDB */
13144
13145 /* Reconfigure the zone */
13146 dns_view_thaw(view);
13147 result = configure_zone(cfg->config, zoneobj, cfg->vconfig,
13148 server->mctx, view, &server->viewlist,
13149 cfg->actx, true, false, true);
13150 dns_view_freeze(view);
13151
13152 exclusive = false;
13153 isc_task_endexclusive(server->task);
13154
13155 if (result != ISC_R_SUCCESS) {
13156 TCHECK(putstr(text, "configure_zone failed: "));
13157 TCHECK(putstr(text, isc_result_totext(result)));
13158 goto cleanup;
13159 }
13160
13161 /* Is it there yet? */
13162 if (redirect) {
13163 if (view->redirect == NULL)
13164 CHECK(ISC_R_NOTFOUND);
13165 dns_zone_attach(view->redirect, &zone);
13166 } else
13167 CHECK(dns_zt_find(view->zonetable, name, 0, NULL, &zone));
13168
13169
13170
13171#ifndef HAVE_LMDB
13172 /* Remove old zone from configuration (and NZF file if applicable) */
13173 if (added) {
13174 result = delete_zoneconf(view, cfg->add_parser,
13175 cfg->nzf_config,
13176 dns_zone_getorigin(zone),
13177 nzf_writeconf);
13178 if (result != ISC_R_SUCCESS) {
13179 TCHECK(putstr(text, "former zone configuration "
13180 "not deleted: "));
13181 TCHECK(putstr(text, isc_result_totext(result)));
13182 goto cleanup;
13183 }
13184 }
13185#endif /* HAVE_LMDB */
13186
13187 if (!added) {
13188 if (cfg->vconfig == NULL) {
13189 result = delete_zoneconf(view, cfg->conf_parser,
13190 cfg->config,
13191 dns_zone_getorigin(zone),
13192 NULL);
13193 } else {
13194 const cfg_obj_t *voptions =
13195 cfg_tuple_get(cfg->vconfig, "options");
13196 result = delete_zoneconf(view, cfg->conf_parser,
13197 voptions,
13198 dns_zone_getorigin(zone),
13199 NULL);
13200 }
13201
13202 if (result != ISC_R_SUCCESS) {
13203 TCHECK(putstr(text, "former zone configuration "
13204 "not deleted: "));
13205 TCHECK(putstr(text, isc_result_totext(result)));
13206 goto cleanup;
13207 }
13208 }
13209
13210 /* Load the zone from the master file if it needs reloading. */
13211 result = dns_zone_load(zone, true);
13212
13213 /*
13214 * Dynamic zones need no reloading, so we can pass this result.
13215 */
13216 if (result == DNS_R_DYNAMIC)
13217 result = ISC_R_SUCCESS;
13218
13219 if (result != ISC_R_SUCCESS) {
13220 dns_db_t *dbp = NULL;
13221
13222 TCHECK(putstr(text, "failed to load zone '"));
13223 TCHECK(putstr(text, zname));
13224 TCHECK(putstr(text, "': "));
13225 TCHECK(putstr(text, isc_result_totext(result)));
13226 TCHECK(putstr(text, "\nThe zone is no longer being served. "));
13227 TCHECK(putstr(text, "Use 'rndc addzone' to correct\n"));
13228 TCHECK(putstr(text, "the problem and restore service."));
13229
13230 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13231 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13232 "modzone failed; removing zone.");
13233
13234 /* If the zone loaded partially, unload it */
13235 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13236 dns_db_detach(&dbp);
13237 dns_zone_unload(zone);
13238 }
13239
13240 /* Remove the zone from the zone table */
13241 dns_zt_unmount(view->zonetable, zone);
13242 goto cleanup;
13243 }
13244
13245#ifndef HAVE_LMDB
13246 /* Store the new zone configuration; also in NZF if applicable */
13247 DE_CONST(zoneobj, z);
13248 CHECK(cfg_parser_mapadd(cfg->add_parser, cfg->nzf_config, z, "zone"));
13249#endif /* HAVE_LMDB */
13250
13251 if (added) {
13252#ifdef HAVE_LMDB
13253 CHECK(nzd_open(view, 0, &txn, &dbi));
13254 CHECK(nzd_save(&txn, dbi, zone, zoneobj));
13255#else
13256 result = nzf_append(view, zoneobj);
13257 if (result != ISC_R_SUCCESS) {
13258 TCHECK(putstr(text, "\nNew zone config not saved: "));
13259 TCHECK(putstr(text, isc_result_totext(result)));
13260 goto cleanup;
13261 }
13262#endif /* HAVE_LMDB */
13263
13264 TCHECK(putstr(text, "zone '"));
13265 TCHECK(putstr(text, zname));
13266 TCHECK(putstr(text, "' reconfigured."));
13267
13268 } else {
13269 TCHECK(putstr(text, "zone '"));
13270 TCHECK(putstr(text, zname));
13271 TCHECK(putstr(text, "' must also be reconfigured in\n"));
13272 TCHECK(putstr(text, "named.conf to make changes permanent."));
13273 }
13274
13275 cleanup:
13276 if (exclusive)
13277 isc_task_endexclusive(server->task);
13278
13279#ifndef HAVE_LMDB
13280 if (fp != NULL)
13281 (void)isc_stdio_close(fp);
13282#else /* HAVE_LMDB */
13283 if (txn != NULL)
13284 (void) nzd_close(&txn, false);
13285#endif /* HAVE_LMDB */
13286
13287 if (zone != NULL)
13288 dns_zone_detach(&zone);
13289
13290 return (result);
13291}
13292
13293/*
13294 * Act on an "addzone" or "modzone" command from the command channel.
13295 */
13296isc_result_t
13297named_server_changezone(named_server_t *server, char *command,
13298 isc_buffer_t **text)
13299{
13300 isc_result_t result;
13301 bool addzone;
13302 bool redirect = false;
13303 ns_cfgctx_t *cfg = NULL;
13304 cfg_obj_t *zoneconf = NULL;
13305 const cfg_obj_t *zoneobj = NULL;
13306 const char *zonename;
13307 dns_view_t *view = NULL;
13308 isc_buffer_t buf;
13309 dns_fixedname_t fname;
13310 dns_name_t *dnsname;
13311
13312 if (strncasecmp(command, "add", 3) == 0)
13313 addzone = true;
13314 else {
13315 INSIST(strncasecmp(command, "mod", 3) == 0);
13316 addzone = false;
13317 }
13318
13319 CHECK(newzone_parse(server, command, &view, &zoneconf,
13320 &zoneobj, &redirect, text));
13321
13322 /* Are we accepting new zones in this view? */
13323#ifdef HAVE_LMDB
13324 if (view->new_zone_db == NULL)
13325#else
13326 if (view->new_zone_file == NULL)
13327#endif /* HAVE_LMDB */
13328 {
13329 (void) putstr(text, "Not allowing new zones in view '");
13330 (void) putstr(text, view->name);
13331 (void) putstr(text, "'");
13332 result = ISC_R_NOPERM;
13333 goto cleanup;
13334 }
13335
13336 cfg = (ns_cfgctx_t *) view->new_zone_config;
13337 if (cfg == NULL) {
13338 result = ISC_R_FAILURE;
13339 goto cleanup;
13340 }
13341
13342 zonename = cfg_obj_asstring(cfg_tuple_get(zoneobj, "name"));
13343 isc_buffer_constinit(&buf, zonename, strlen(zonename));
13344 isc_buffer_add(&buf, strlen(zonename));
13345
13346 dnsname = dns_fixedname_initname(&fname);
13347 CHECK(dns_name_fromtext(dnsname, &buf, dns_rootname, 0, NULL));
13348
13349 if (redirect) {
13350 if (!dns_name_equal(dnsname, dns_rootname)) {
13351 (void) putstr(text,
13352 "redirect zones must be called \".\"");
13353 CHECK(ISC_R_FAILURE);
13354 }
13355 }
13356
13357 if (addzone)
13358 CHECK(do_addzone(server, cfg, view, dnsname, zoneconf,
13359 zoneobj, redirect, text));
13360 else
13361 CHECK(do_modzone(server, cfg, view, dnsname, zonename,
13362 zoneobj, redirect, text));
13363
13364 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13365 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13366 "%s zone %s in view %s via %s",
13367 addzone ? "added" : "updated",
13368 zonename, view->name,
13369 addzone ? NAMED_COMMAND_ADDZONE : NAMED_COMMAND_MODZONE);
13370
13371 /* Changing a zone counts as reconfiguration */
13372 CHECK(isc_time_now(&named_g_configtime));
13373
13374 cleanup:
13375 if (isc_buffer_usedlength(*text) > 0)
13376 (void) putnull(text);
13377 if (zoneconf != NULL)
13378 cfg_obj_destroy(named_g_addparser, &zoneconf);
13379 if (view != NULL)
13380 dns_view_detach(&view);
13381
13382 return (result);
13383}
13384
13385static bool
13386inuse(const char* file, bool first, isc_buffer_t **text) {
13387 if (file != NULL && isc_file_exists(file)) {
13388 if (first)
13389 (void) putstr(text,
13390 "The following files were in use "
13391 "and may now be removed:\n");
13392 else
13393 (void) putstr(text, "\n");
13394 (void) putstr(text, file);
13395 (void) putnull(text);
13396 return (false);
13397 }
13398 return (first);
13399}
13400
13401typedef struct {
13402 dns_zone_t *zone;
13403 bool cleanup;
13404} ns_dzctx_t;
13405
13406/*
13407 * Carry out a zone deletion scheduled by named_server_delzone().
13408 */
13409static void
13410rmzone(isc_task_t *task, isc_event_t *event) {
13411 ns_dzctx_t *dz = (ns_dzctx_t *)event->ev_arg;
13412 dns_zone_t *zone, *raw = NULL, *mayberaw;
13413 char zonename[DNS_NAME_FORMATSIZE];
13414 dns_view_t *view;
13415 ns_cfgctx_t *cfg;
13416 dns_db_t *dbp = NULL;
13417 bool added;
13418 isc_result_t result;
13419#ifdef HAVE_LMDB
13420 MDB_txn *txn = NULL;
13421 MDB_dbi dbi;
13422#endif
13423
13424 REQUIRE(dz != NULL);
13425
13426 isc_event_free(&event);
13427
13428 /* Dig out configuration for this zone */
13429 zone = dz->zone;
13430 view = dns_zone_getview(zone);
13431 cfg = (ns_cfgctx_t *) view->new_zone_config;
13432 dns_name_format(dns_zone_getorigin(zone), zonename, sizeof(zonename));
13433
13434 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13435 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13436 "deleting zone %s in view %s via delzone",
13437 zonename, view->name);
13438
13439 /* Remove the zone from configuration (and NZF file if applicable) */
13440 added = dns_zone_getadded(zone);
13441
13442 if (added && cfg != NULL) {
13443#ifdef HAVE_LMDB
13444 /* Make sure we can open the NZD database */
13445 result = nzd_open(view, 0, &txn, &dbi);
13446 if (result != ISC_R_SUCCESS) {
13447 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13448 NAMED_LOGMODULE_SERVER,
13449 ISC_LOG_ERROR,
13450 "unable to open NZD database for '%s'",
13451 view->new_zone_db);
13452 } else {
13453 result = nzd_save(&txn, dbi, zone, NULL);
13454 }
13455
13456 if (result != ISC_R_SUCCESS) {
13457 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13458 NAMED_LOGMODULE_SERVER,
13459 ISC_LOG_ERROR, "unable to "
13460 "delete zone configuration: %s",
13461 isc_result_totext(result));
13462 }
13463#else
13464 result = delete_zoneconf(view, cfg->add_parser,
13465 cfg->nzf_config,
13466 dns_zone_getorigin(zone),
13467 nzf_writeconf);
13468 if (result != ISC_R_SUCCESS) {
13469 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13470 NAMED_LOGMODULE_SERVER,
13471 ISC_LOG_ERROR, "unable to "
13472 "delete zone configuration: %s",
13473 isc_result_totext(result));
13474 }
13475#endif /* HAVE_LMDB */
13476 }
13477
13478 if (!added && cfg != NULL) {
13479 if (cfg->vconfig != NULL) {
13480 const cfg_obj_t *voptions =
13481 cfg_tuple_get(cfg->vconfig, "options");
13482 result = delete_zoneconf(view, cfg->conf_parser,
13483 voptions,
13484 dns_zone_getorigin(zone),
13485 NULL);
13486 } else {
13487 result = delete_zoneconf(view, cfg->conf_parser,
13488 cfg->config,
13489 dns_zone_getorigin(zone),
13490 NULL);
13491 }
13492 if (result != ISC_R_SUCCESS){
13493 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13494 NAMED_LOGMODULE_SERVER,
13495 ISC_LOG_ERROR, "unable to "
13496 "delete zone configuration: %s",
13497 isc_result_totext(result));
13498 }
13499 }
13500
13501 /* Unload zone database */
13502 if (dns_zone_getdb(zone, &dbp) == ISC_R_SUCCESS) {
13503 dns_db_detach(&dbp);
13504 dns_zone_unload(zone);
13505 }
13506
13507 /* Clean up stub/slave zone files if requested to do so */
13508 dns_zone_getraw(zone, &raw);
13509 mayberaw = (raw != NULL) ? raw : zone;
13510
13511 if (added && dz->cleanup) {
13512 const char *file;
13513
13514 file = dns_zone_getfile(mayberaw);
13515 result = isc_file_remove(file);
13516 if (result != ISC_R_SUCCESS) {
13517 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13518 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13519 "file %s not removed: %s",
13520 file, isc_result_totext(result));
13521 }
13522
13523 file = dns_zone_getjournal(mayberaw);
13524 result = isc_file_remove(file);
13525 if (result != ISC_R_SUCCESS) {
13526 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13527 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
13528 "file %s not removed: %s",
13529 file, isc_result_totext(result));
13530 }
13531
13532 if (zone != mayberaw) {
13533 file = dns_zone_getfile(zone);
13534 result = isc_file_remove(file);
13535 if (result != ISC_R_SUCCESS) {
13536 isc_log_write(named_g_lctx,
13537 NAMED_LOGCATEGORY_GENERAL,
13538 NAMED_LOGMODULE_SERVER,
13539 ISC_LOG_WARNING,
13540 "file %s not removed: %s",
13541 file, isc_result_totext(result));
13542 }
13543
13544 file = dns_zone_getjournal(zone);
13545 result = isc_file_remove(file);
13546 if (result != ISC_R_SUCCESS) {
13547 isc_log_write(named_g_lctx,
13548 NAMED_LOGCATEGORY_GENERAL,
13549 NAMED_LOGMODULE_SERVER,
13550 ISC_LOG_WARNING,
13551 "file %s not removed: %s",
13552 file, isc_result_totext(result));
13553 }
13554 }
13555 }
13556
13557#ifdef HAVE_LMDB
13558 if (txn != NULL)
13559 (void) nzd_close(&txn, false);
13560#endif
13561 if (raw != NULL)
13562 dns_zone_detach(&raw);
13563 dns_zone_detach(&zone);
13564 isc_mem_put(named_g_mctx, dz, sizeof(*dz));
13565 isc_task_detach(&task);
13566}
13567
13568/*
13569 * Act on a "delzone" command from the command channel.
13570 */
13571isc_result_t
13572named_server_delzone(named_server_t *server, isc_lex_t *lex,
13573 isc_buffer_t **text)
13574{
13575 isc_result_t result, tresult;
13576 dns_zone_t *zone = NULL;
13577 dns_zone_t *raw = NULL;
13578 dns_zone_t *mayberaw;
13579 dns_view_t *view = NULL;
13580 char zonename[DNS_NAME_FORMATSIZE];
13581 bool cleanup = false;
13582 const char *ptr;
13583 bool added;
13584 ns_dzctx_t *dz = NULL;
13585 isc_event_t *dzevent = NULL;
13586 isc_task_t *task = NULL;
13587
13588 /* Skip the command name. */
13589 ptr = next_token(lex, text);
13590 if (ptr == NULL)
13591 return (ISC_R_UNEXPECTEDEND);
13592
13593 /* Find out what we are to do. */
13594 ptr = next_token(lex, text);
13595 if (ptr == NULL)
13596 return (ISC_R_UNEXPECTEDEND);
13597
13598 if (strcmp(ptr, "-clean") == 0 || strcmp(ptr, "-clear") == 0) {
13599 cleanup = true;
13600 ptr = next_token(lex, text);
13601 }
13602
13603 CHECK(zone_from_args(server, lex, ptr, &zone, zonename,
13604 text, false));
13605 if (zone == NULL) {
13606 result = ISC_R_UNEXPECTEDEND;
13607 goto cleanup;
13608 }
13609
13610 INSIST(zonename != NULL);
13611
13612 /* Is this a policy zone? */
13613 if (dns_zone_get_rpz_num(zone) != DNS_RPZ_INVALID_NUM) {
13614 TCHECK(putstr(text, "zone '"));
13615 TCHECK(putstr(text, zonename));
13616 TCHECK(putstr(text,
13617 "' cannot be deleted: response-policy zone."));
13618 result = ISC_R_FAILURE;
13619 goto cleanup;
13620 }
13621
13622 view = dns_zone_getview(zone);
13623 if (dns_zone_gettype(zone) == dns_zone_redirect)
13624 dns_zone_detach(&view->redirect);
13625 else
13626 CHECK(dns_zt_unmount(view->zonetable, zone));
13627
13628 /* Send cleanup event */
13629 dz = isc_mem_get(named_g_mctx, sizeof(*dz));
13630 if (dz == NULL)
13631 CHECK(ISC_R_NOMEMORY);
13632
13633 dz->cleanup = cleanup;
13634 dz->zone = NULL;
13635 dns_zone_attach(zone, &dz->zone);
13636 dzevent = isc_event_allocate(named_g_mctx, server, NAMED_EVENT_DELZONE,
13637 rmzone, dz, sizeof(isc_event_t));
13638 if (dzevent == NULL)
13639 CHECK(ISC_R_NOMEMORY);
13640
13641 dns_zone_gettask(zone, &task);
13642 isc_task_send(task, &dzevent);
13643 dz = NULL;
13644
13645 /* Inform user about cleaning up stub/slave zone files */
13646 dns_zone_getraw(zone, &raw);
13647 mayberaw = (raw != NULL) ? raw : zone;
13648
13649 added = dns_zone_getadded(zone);
13650 if (!added) {
13651 TCHECK(putstr(text, "zone '"));
13652 TCHECK(putstr(text, zonename));
13653 TCHECK(putstr(text,
13654 "' is no longer active and will be deleted.\n"));
13655 TCHECK(putstr(text, "To keep it from returning "));
13656 TCHECK(putstr(text, "when the server is restarted, it\n"));
13657 TCHECK(putstr(text, "must also be removed from named.conf."));
13658 } else if (cleanup) {
13659 TCHECK(putstr(text, "zone '"));
13660 TCHECK(putstr(text, zonename));
13661 TCHECK(putstr(text, "' and associated files will be deleted."));
13662 } else if (dns_zone_gettype(mayberaw) == dns_zone_slave ||
13663 dns_zone_gettype(mayberaw) == dns_zone_mirror ||
13664 dns_zone_gettype(mayberaw) == dns_zone_stub)
13665 {
13666 bool first;
13667 const char *file;
13668
13669 TCHECK(putstr(text, "zone '"));
13670 TCHECK(putstr(text, zonename));
13671 TCHECK(putstr(text, "' will be deleted."));
13672
13673 file = dns_zone_getfile(mayberaw);
13674 first = inuse(file, true, text);
13675
13676 file = dns_zone_getjournal(mayberaw);
13677 first = inuse(file, first, text);
13678
13679 if (zone != mayberaw) {
13680 file = dns_zone_getfile(zone);
13681 first = inuse(file, first, text);
13682
13683 file = dns_zone_getjournal(zone);
13684 (void) inuse(file, first, text);
13685 }
13686 }
13687
13688 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13689 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13690 "zone %s scheduled for removal via delzone", zonename);
13691
13692 /* Removing a zone counts as reconfiguration */
13693 CHECK(isc_time_now(&named_g_configtime));
13694
13695 result = ISC_R_SUCCESS;
13696
13697 cleanup:
13698 if (isc_buffer_usedlength(*text) > 0)
13699 (void) putnull(text);
13700 if (raw != NULL)
13701 dns_zone_detach(&raw);
13702 if (zone != NULL)
13703 dns_zone_detach(&zone);
13704 if (dz != NULL) {
13705 dns_zone_detach(&dz->zone);
13706 isc_mem_put(named_g_mctx, dz, sizeof(*dz));
13707 }
13708
13709 return (result);
13710}
13711
13712static const cfg_obj_t *
13713find_name_in_list_from_map(const cfg_obj_t *config,
13714 const char *map_key_for_list,
13715 const char *name, bool redirect)
13716{
13717 const cfg_obj_t *list = NULL;
13718 const cfg_listelt_t *element;
13719 const cfg_obj_t *obj = NULL;
13720 dns_fixedname_t fixed1, fixed2;
13721 dns_name_t *name1 = NULL, *name2 = NULL;
13722 isc_result_t result;
13723
13724 if (strcmp(map_key_for_list, "zone") == 0) {
13725 name1 = dns_fixedname_initname(&fixed1);
13726 name2 = dns_fixedname_initname(&fixed2);
13727 result = dns_name_fromstring(name1, name, 0, NULL);
13728 RUNTIME_CHECK(result == ISC_R_SUCCESS);
13729 }
13730
13731 cfg_map_get(config, map_key_for_list, &list);
13732 for (element = cfg_list_first(list);
13733 element != NULL;
13734 element = cfg_list_next(element))
13735 {
13736 const char *vname;
13737
13738 obj = cfg_listelt_value(element);
13739 INSIST(obj != NULL);
13740 vname = cfg_obj_asstring(cfg_tuple_get(obj, "name"));
13741 if (vname == NULL) {
13742 obj = NULL;
13743 continue;
13744 }
13745
13746 if (name1 != NULL) {
13747 result = dns_name_fromstring(name2, vname, 0, NULL);
13748 if (result == ISC_R_SUCCESS &&
13749 dns_name_equal(name1, name2)) {
13750 const cfg_obj_t *zoptions;
13751 const cfg_obj_t *typeobj = NULL;
13752 zoptions = cfg_tuple_get(obj, "options");
13753
13754 if (zoptions != NULL)
13755 cfg_map_get(zoptions, "type", &typeobj);
13756 if (redirect && typeobj != NULL &&
13757 strcasecmp(cfg_obj_asstring(typeobj),
13758 "redirect") == 0)
13759 break;
13760 else if (!redirect)
13761 break;
13762 }
13763 } else if (strcasecmp(vname, name) == 0)
13764 break;
13765
13766 obj = NULL;
13767 }
13768
13769 return (obj);
13770}
13771
13772static void
13773emitzone(void *arg, const char *buf, int len) {
13774 ns_dzarg_t *dzarg = arg;
13775 isc_result_t result;
13776
13777 REQUIRE(dzarg != NULL && ISC_MAGIC_VALID(dzarg, DZARG_MAGIC));
13778 result = putmem(dzarg->text, buf, len);
13779 if (result != ISC_R_SUCCESS && dzarg->result == ISC_R_SUCCESS) {
13780 dzarg->result = result;
13781 }
13782}
13783
13784/*
13785 * Act on a "showzone" command from the command channel.
13786 */
13787isc_result_t
13788named_server_showzone(named_server_t *server, isc_lex_t *lex,
13789 isc_buffer_t **text)
13790{
13791 isc_result_t result;
13792 const cfg_obj_t *vconfig = NULL, *zconfig = NULL;
13793 char zonename[DNS_NAME_FORMATSIZE];
13794 const cfg_obj_t *map;
13795 dns_view_t *view = NULL;
13796 dns_zone_t *zone = NULL;
13797 ns_cfgctx_t *cfg = NULL;
13798 bool exclusive = false;
13799#ifdef HAVE_LMDB
13800 cfg_obj_t *nzconfig = NULL;
13801#endif /* HAVE_LMDB */
13802 bool added, redirect;
13803 ns_dzarg_t dzarg;
13804
13805 /* Parse parameters */
13806 CHECK(zone_from_args(server, lex, NULL, &zone, zonename,
13807 text, true));
13808 if (zone == NULL) {
13809 result = ISC_R_UNEXPECTEDEND;
13810 goto cleanup;
13811 }
13812
13813 redirect = dns_zone_gettype(zone) == dns_zone_redirect;
13814 added = dns_zone_getadded(zone);
13815 view = dns_zone_getview(zone);
13816 dns_zone_detach(&zone);
13817
13818 cfg = (ns_cfgctx_t *) view->new_zone_config;
13819 if (cfg == NULL) {
13820 result = ISC_R_FAILURE;
13821 goto cleanup;
13822 }
13823
13824 result = isc_task_beginexclusive(server->task);
13825 RUNTIME_CHECK(result == ISC_R_SUCCESS);
13826 exclusive = true;
13827
13828 if (!added) {
13829 /* Find the view statement */
13830 vconfig = find_name_in_list_from_map(cfg->config, "view",
13831 view->name, false);
13832
13833 /* Find the zone statement */
13834 if (vconfig != NULL)
13835 map = cfg_tuple_get(vconfig, "options");
13836 else
13837 map = cfg->config;
13838
13839 zconfig = find_name_in_list_from_map(map, "zone", zonename,
13840 redirect);
13841 }
13842
13843#ifndef HAVE_LMDB
13844 if (zconfig == NULL && cfg->nzf_config != NULL)
13845 zconfig = find_name_in_list_from_map(cfg->nzf_config,
13846 "zone", zonename,
13847 redirect);
13848#else /* HAVE_LMDB */
13849 if (zconfig == NULL) {
13850 const cfg_obj_t *zlist = NULL;
13851 CHECK(get_newzone_config(view, zonename, &nzconfig));
13852 CHECK(cfg_map_get(nzconfig, "zone", &zlist));
13853 if (!cfg_obj_islist(zlist))
13854 CHECK(ISC_R_FAILURE);
13855
13856 zconfig = cfg_listelt_value(cfg_list_first(zlist));
13857 }
13858#endif /* HAVE_LMDB */
13859
13860 if (zconfig == NULL)
13861 CHECK(ISC_R_NOTFOUND);
13862
13863 CHECK(putstr(text, "zone "));
13864 dzarg.magic = DZARG_MAGIC;
13865 dzarg.text = text;
13866 dzarg.result = ISC_R_SUCCESS;
13867 cfg_printx(zconfig, CFG_PRINTER_ONELINE, emitzone, &dzarg);
13868 CHECK(dzarg.result);
13869
13870 CHECK(putstr(text, ";"));
13871
13872 result = ISC_R_SUCCESS;
13873
13874 cleanup:
13875#ifdef HAVE_LMDB
13876 if (nzconfig != NULL)
13877 cfg_obj_destroy(named_g_addparser, &nzconfig);
13878#endif /* HAVE_LMDB */
13879 if (isc_buffer_usedlength(*text) > 0)
13880 (void) putnull(text);
13881 if (exclusive)
13882 isc_task_endexclusive(server->task);
13883
13884 return (result);
13885}
13886
13887static void
13888newzone_cfgctx_destroy(void **cfgp) {
13889 ns_cfgctx_t *cfg;
13890
13891 REQUIRE(cfgp != NULL && *cfgp != NULL);
13892
13893 cfg = *cfgp;
13894
13895 if (cfg->conf_parser != NULL) {
13896 if (cfg->config != NULL)
13897 cfg_obj_destroy(cfg->conf_parser, &cfg->config);
13898 if (cfg->vconfig != NULL)
13899 cfg_obj_destroy(cfg->conf_parser, &cfg->vconfig);
13900 cfg_parser_destroy(&cfg->conf_parser);
13901 }
13902 if (cfg->add_parser != NULL) {
13903 if (cfg->nzf_config != NULL)
13904 cfg_obj_destroy(cfg->add_parser, &cfg->nzf_config);
13905 cfg_parser_destroy(&cfg->add_parser);
13906 }
13907
13908 if (cfg->actx != NULL)
13909 cfg_aclconfctx_detach(&cfg->actx);
13910
13911 isc_mem_putanddetach(&cfg->mctx, cfg, sizeof(*cfg));
13912 *cfgp = NULL;
13913}
13914
13915static isc_result_t
13916generate_salt(unsigned char *salt, size_t saltlen) {
13917 unsigned char text[512 + 1];
13918 isc_region_t r;
13919 isc_buffer_t buf;
13920 isc_result_t result;
13921
13922 if (saltlen > 256U)
13923 return (ISC_R_RANGE);
13924
13925 isc_nonce_buf(salt, saltlen);
13926
13927 r.base = salt;
13928 r.length = (unsigned int) saltlen;
13929
13930 isc_buffer_init(&buf, text, sizeof(text));
13931 result = isc_hex_totext(&r, 2, "", &buf);
13932 RUNTIME_CHECK(result == ISC_R_SUCCESS);
13933 text[saltlen * 2] = 0;
13934
13935 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
13936 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
13937 "generated salt: %s", text);
13938
13939 return (ISC_R_SUCCESS);
13940}
13941
13942isc_result_t
13943named_server_signing(named_server_t *server, isc_lex_t *lex,
13944 isc_buffer_t **text)
13945{
13946 isc_result_t result = ISC_R_SUCCESS;
13947 dns_zone_t *zone = NULL;
13948 dns_name_t *origin;
13949 dns_db_t *db = NULL;
13950 dns_dbnode_t *node = NULL;
13951 dns_dbversion_t *version = NULL;
13952 dns_rdatatype_t privatetype;
13953 dns_rdataset_t privset;
13954 bool first = true;
13955 bool list = false, clear = false;
13956 bool chain = false;
13957 bool setserial = false;
13958 uint32_t serial = 0;
13959 char keystr[DNS_SECALG_FORMATSIZE + 7]; /* <5-digit keyid>/<alg> */
13960 unsigned short hash = 0, flags = 0, iter = 0, saltlen = 0;
13961 unsigned char salt[255];
13962 const char *ptr;
13963 size_t n;
13964
13965 dns_rdataset_init(&privset);
13966
13967 /* Skip the command name. */
13968 ptr = next_token(lex, text);
13969 if (ptr == NULL)
13970 return (ISC_R_UNEXPECTEDEND);
13971
13972 /* Find out what we are to do. */
13973 ptr = next_token(lex, text);
13974 if (ptr == NULL)
13975 return (ISC_R_UNEXPECTEDEND);
13976
13977 if (strcasecmp(ptr, "-list") == 0)
13978 list = true;
13979 else if ((strcasecmp(ptr, "-clear") == 0) ||
13980 (strcasecmp(ptr, "-clean") == 0))
13981 {
13982 clear = true;
13983 ptr = next_token(lex, text);
13984 if (ptr == NULL)
13985 return (ISC_R_UNEXPECTEDEND);
13986 strlcpy(keystr, ptr, sizeof(keystr));
13987 } else if (strcasecmp(ptr, "-nsec3param") == 0) {
13988 char hashbuf[64], flagbuf[64], iterbuf[64];
13989 char nbuf[256];
13990
13991 chain = true;
13992 ptr = next_token(lex, text);
13993 if (ptr == NULL)
13994 return (ISC_R_UNEXPECTEDEND);
13995
13996 if (strcasecmp(ptr, "none") == 0)
13997 hash = 0;
13998 else {
13999 strlcpy(hashbuf, ptr, sizeof(hashbuf));
14000
14001 ptr = next_token(lex, text);
14002 if (ptr == NULL)
14003 return (ISC_R_UNEXPECTEDEND);
14004 strlcpy(flagbuf, ptr, sizeof(flagbuf));
14005
14006 ptr = next_token(lex, text);
14007 if (ptr == NULL)
14008 return (ISC_R_UNEXPECTEDEND);
14009 strlcpy(iterbuf, ptr, sizeof(iterbuf));
14010
14011 n = snprintf(nbuf, sizeof(nbuf), "%s %s %s",
14012 hashbuf, flagbuf, iterbuf);
14013 if (n == sizeof(nbuf))
14014 return (ISC_R_NOSPACE);
14015 n = sscanf(nbuf, "%hu %hu %hu", &hash, &flags, &iter);
14016 if (n != 3U)
14017 return (ISC_R_BADNUMBER);
14018
14019 if (hash > 0xffU || flags > 0xffU)
14020 return (ISC_R_RANGE);
14021
14022 ptr = next_token(lex, text);
14023 if (ptr == NULL) {
14024 return (ISC_R_UNEXPECTEDEND);
14025 } else if (strcasecmp(ptr, "auto") == 0) {
14026 /* Auto-generate a random salt.
14027 * XXXMUKS: This currently uses the
14028 * minimum recommended length by RFC
14029 * 5155 (64 bits). It should be made
14030 * configurable.
14031 */
14032 saltlen = 8;
14033 CHECK(generate_salt(salt, saltlen));
14034 } else if (strcmp(ptr, "-") != 0) {
14035 isc_buffer_t buf;
14036
14037 isc_buffer_init(&buf, salt, sizeof(salt));
14038 CHECK(isc_hex_decodestring(ptr, &buf));
14039 saltlen = isc_buffer_usedlength(&buf);
14040 }
14041 }
14042 } else if (strcasecmp(ptr, "-serial") == 0) {
14043 ptr = next_token(lex, text);
14044 if (ptr == NULL)
14045 return (ISC_R_UNEXPECTEDEND);
14046 CHECK(isc_parse_uint32(&serial, ptr, 10));
14047 setserial = true;
14048 } else
14049 CHECK(DNS_R_SYNTAX);
14050
14051 CHECK(zone_from_args(server, lex, NULL, &zone, NULL,
14052 text, false));
14053 if (zone == NULL)
14054 CHECK(ISC_R_UNEXPECTEDEND);
14055
14056 if (clear) {
14057 CHECK(dns_zone_keydone(zone, keystr));
14058 (void) putstr(text, "request queued");
14059 (void) putnull(text);
14060 } else if (chain) {
14061 CHECK(dns_zone_setnsec3param(zone, (uint8_t)hash,
14062 (uint8_t)flags, iter,
14063 (uint8_t)saltlen, salt,
14064 true));
14065 (void) putstr(text, "nsec3param request queued");
14066 (void) putnull(text);
14067 } else if (setserial) {
14068 CHECK(dns_zone_setserial(zone, serial));
14069 (void) putstr(text, "serial request queued");
14070 (void) putnull(text);
14071 } else if (list) {
14072 privatetype = dns_zone_getprivatetype(zone);
14073 origin = dns_zone_getorigin(zone);
14074 CHECK(dns_zone_getdb(zone, &db));
14075 CHECK(dns_db_findnode(db, origin, false, &node));
14076 dns_db_currentversion(db, &version);
14077
14078 result = dns_db_findrdataset(db, node, version, privatetype,
14079 dns_rdatatype_none, 0,
14080 &privset, NULL);
14081 if (result == ISC_R_NOTFOUND) {
14082 (void) putstr(text, "No signing records found");
14083 (void) putnull(text);
14084 result = ISC_R_SUCCESS;
14085 goto cleanup;
14086 }
14087
14088 for (result = dns_rdataset_first(&privset);
14089 result == ISC_R_SUCCESS;
14090 result = dns_rdataset_next(&privset))
14091 {
14092 dns_rdata_t priv = DNS_RDATA_INIT;
14093 char output[BUFSIZ];
14094 isc_buffer_t buf;
14095
14096 dns_rdataset_current(&privset, &priv);
14097
14098 isc_buffer_init(&buf, output, sizeof(output));
14099 CHECK(dns_private_totext(&priv, &buf));
14100 if (!first)
14101 CHECK(putstr(text, "\n"));
14102 CHECK(putstr(text, output));
14103 first = false;
14104 }
14105 if (!first)
14106 CHECK(putnull(text));
14107
14108 if (result == ISC_R_NOMORE)
14109 result = ISC_R_SUCCESS;
14110 }
14111
14112 cleanup:
14113 if (dns_rdataset_isassociated(&privset))
14114 dns_rdataset_disassociate(&privset);
14115 if (node != NULL)
14116 dns_db_detachnode(db, &node);
14117 if (version != NULL)
14118 dns_db_closeversion(db, &version, false);
14119 if (db != NULL)
14120 dns_db_detach(&db);
14121 if (zone != NULL)
14122 dns_zone_detach(&zone);
14123
14124 return (result);
14125}
14126
14127static isc_result_t
14128putmem(isc_buffer_t **b, const char *str, size_t len) {
14129 isc_result_t result;
14130
14131 result = isc_buffer_reserve(b, (unsigned int)len);
14132 if (result != ISC_R_SUCCESS)
14133 return (ISC_R_NOSPACE);
14134
14135 isc_buffer_putmem(*b, (const unsigned char *)str, (unsigned int)len);
14136 return (ISC_R_SUCCESS);
14137}
14138
14139static inline isc_result_t
14140putstr(isc_buffer_t **b, const char *str) {
14141 return (putmem(b, str, strlen(str)));
14142}
14143
14144static isc_result_t
14145putuint8(isc_buffer_t **b, uint8_t val) {
14146 isc_result_t result;
14147
14148 result = isc_buffer_reserve(b, 1);
14149 if (result != ISC_R_SUCCESS)
14150 return (ISC_R_NOSPACE);
14151
14152 isc_buffer_putuint8(*b, val);
14153 return (ISC_R_SUCCESS);
14154}
14155
14156static inline isc_result_t
14157putnull(isc_buffer_t **b) {
14158 return (putuint8(b, 0));
14159}
14160
14161isc_result_t
14162named_server_zonestatus(named_server_t *server, isc_lex_t *lex,
14163 isc_buffer_t **text)
14164{
14165 isc_result_t result = ISC_R_SUCCESS;
14166 dns_zone_t *zone = NULL, *raw = NULL, *mayberaw = NULL;
14167 const char *type, *file;
14168 char zonename[DNS_NAME_FORMATSIZE];
14169 uint32_t serial, signed_serial, nodes;
14170 char serbuf[16], sserbuf[16], nodebuf[16];
14171 char resignbuf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE + 2];
14172 char lbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
14173 char xbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
14174 char rbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
14175 char kbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
14176 char rtbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
14177 isc_time_t loadtime, expiretime, refreshtime;
14178 isc_time_t refreshkeytime, resigntime;
14179 dns_zonetype_t zonetype;
14180 bool dynamic = false, frozen = false;
14181 bool hasraw = false;
14182 bool secure, maintain, allow;
14183 dns_db_t *db = NULL, *rawdb = NULL;
14184 char **incfiles = NULL;
14185 int nfiles = 0;
14186
14187 isc_time_settoepoch(&loadtime);
14188 isc_time_settoepoch(&refreshtime);
14189 isc_time_settoepoch(&expiretime);
14190 isc_time_settoepoch(&refreshkeytime);
14191 isc_time_settoepoch(&resigntime);
14192
14193 CHECK(zone_from_args(server, lex, NULL, &zone, zonename,
14194 text, true));
14195 if (zone == NULL) {
14196 result = ISC_R_UNEXPECTEDEND;
14197 goto cleanup;
14198 }
14199
14200 /* Inline signing? */
14201 CHECK(dns_zone_getdb(zone, &db));
14202 dns_zone_getraw(zone, &raw);
14203 hasraw = (raw != NULL);
14204 if (hasraw) {
14205 mayberaw = raw;
14206 zonetype = dns_zone_gettype(raw);
14207 CHECK(dns_zone_getdb(raw, &rawdb));
14208 } else {
14209 mayberaw = zone;
14210 zonetype = dns_zone_gettype(zone);
14211 }
14212
14213 switch (zonetype) {
14214 case dns_zone_master:
14215 type = "master";
14216 break;
14217 case dns_zone_slave:
14218 type = "slave";
14219 break;
14220 case dns_zone_mirror:
14221 type = "mirror";
14222 break;
14223 case dns_zone_stub:
14224 type = "stub";
14225 break;
14226 case dns_zone_staticstub:
14227 type = "staticstub";
14228 break;
14229 case dns_zone_redirect:
14230 type = "redirect";
14231 break;
14232 case dns_zone_key:
14233 type = "key";
14234 break;
14235 case dns_zone_dlz:
14236 type = "dlz";
14237 break;
14238 default:
14239 type = "unknown";
14240 }
14241
14242 /* Serial number */
14243 result = dns_zone_getserial(mayberaw, &serial);
14244 /* XXXWPK TODO this is to mirror old behavior with dns_zone_getserial */
14245 if (result != ISC_R_SUCCESS) {
14246 serial = 0;
14247 }
14248 snprintf(serbuf, sizeof(serbuf), "%u", serial);
14249 if (hasraw) {
14250 result = dns_zone_getserial(zone, &signed_serial);
14251 /* XXXWPK TODO ut supra */
14252 if (result != ISC_R_SUCCESS) {
14253 serial = 0;
14254 }
14255 snprintf(sserbuf, sizeof(sserbuf), "%u", signed_serial);
14256 }
14257
14258 /* Database node count */
14259 nodes = dns_db_nodecount(hasraw ? rawdb : db);
14260 snprintf(nodebuf, sizeof(nodebuf), "%u", nodes);
14261
14262 /* Security */
14263 secure = dns_db_issecure(db);
14264 allow = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_ALLOW) != 0);
14265 maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
14266
14267 /* Master files */
14268 file = dns_zone_getfile(mayberaw);
14269 nfiles = dns_zone_getincludes(mayberaw, &incfiles);
14270
14271 /* Load time */
14272 dns_zone_getloadtime(zone, &loadtime);
14273 isc_time_formathttptimestamp(&loadtime, lbuf, sizeof(lbuf));
14274
14275 /* Refresh/expire times */
14276 if (zonetype == dns_zone_slave ||
14277 zonetype == dns_zone_mirror ||
14278 zonetype == dns_zone_stub ||
14279 zonetype == dns_zone_redirect)
14280 {
14281 dns_zone_getexpiretime(mayberaw, &expiretime);
14282 isc_time_formathttptimestamp(&expiretime, xbuf, sizeof(xbuf));
14283 dns_zone_getrefreshtime(mayberaw, &refreshtime);
14284 isc_time_formathttptimestamp(&refreshtime, rbuf, sizeof(rbuf));
14285 }
14286
14287 /* Key refresh time */
14288 if (zonetype == dns_zone_master ||
14289 (zonetype == dns_zone_slave && hasraw))
14290 {
14291 dns_zone_getrefreshkeytime(zone, &refreshkeytime);
14292 isc_time_formathttptimestamp(&refreshkeytime, kbuf,
14293 sizeof(kbuf));
14294 }
14295
14296 /* Dynamic? */
14297 if (zonetype == dns_zone_master) {
14298 dynamic = dns_zone_isdynamic(mayberaw, true);
14299 frozen = dynamic && !dns_zone_isdynamic(mayberaw, false);
14300 }
14301
14302 /* Next resign event */
14303 if (secure && (zonetype == dns_zone_master ||
14304 (zonetype == dns_zone_slave && hasraw)) &&
14305 ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_NORESIGN) == 0))
14306 {
14307 dns_name_t *name;
14308 dns_fixedname_t fixed;
14309 dns_rdataset_t next;
14310
14311 dns_rdataset_init(&next);
14312 name = dns_fixedname_initname(&fixed);
14313
14314 result = dns_db_getsigningtime(db, &next, name);
14315 if (result == ISC_R_SUCCESS) {
14316 isc_stdtime_t timenow;
14317 char namebuf[DNS_NAME_FORMATSIZE];
14318 char typebuf[DNS_RDATATYPE_FORMATSIZE];
14319
14320 isc_stdtime_get(&timenow);
14321 dns_name_format(name, namebuf, sizeof(namebuf));
14322 dns_rdatatype_format(next.covers,
14323 typebuf, sizeof(typebuf));
14324 snprintf(resignbuf, sizeof(resignbuf),
14325 "%s/%s", namebuf, typebuf);
14326 isc_time_set(&resigntime, next.resign -
14327 dns_zone_getsigresigninginterval(zone), 0);
14328 isc_time_formathttptimestamp(&resigntime, rtbuf,
14329 sizeof(rtbuf));
14330 dns_rdataset_disassociate(&next);
14331 }
14332 }
14333
14334 /* Create text */
14335 CHECK(putstr(text, "name: "));
14336 CHECK(putstr(text, zonename));
14337
14338 CHECK(putstr(text, "\ntype: "));
14339 CHECK(putstr(text, type));
14340
14341 if (file != NULL) {
14342 int i;
14343 CHECK(putstr(text, "\nfiles: "));
14344 CHECK(putstr(text, file));
14345 for (i = 0; i < nfiles; i++) {
14346 CHECK(putstr(text, ", "));
14347 if (incfiles[i] != NULL) {
14348 CHECK(putstr(text, incfiles[i]));
14349 }
14350 }
14351 }
14352
14353 CHECK(putstr(text, "\nserial: "));
14354 CHECK(putstr(text, serbuf));
14355 if (hasraw) {
14356 CHECK(putstr(text, "\nsigned serial: "));
14357 CHECK(putstr(text, sserbuf));
14358 }
14359
14360 CHECK(putstr(text, "\nnodes: "));
14361 CHECK(putstr(text, nodebuf));
14362
14363 if (! isc_time_isepoch(&loadtime)) {
14364 CHECK(putstr(text, "\nlast loaded: "));
14365 CHECK(putstr(text, lbuf));
14366 }
14367
14368 if (! isc_time_isepoch(&refreshtime)) {
14369 CHECK(putstr(text, "\nnext refresh: "));
14370 CHECK(putstr(text, rbuf));
14371 }
14372
14373 if (! isc_time_isepoch(&expiretime)) {
14374 CHECK(putstr(text, "\nexpires: "));
14375 CHECK(putstr(text, xbuf));
14376 }
14377
14378 if (secure) {
14379 CHECK(putstr(text, "\nsecure: yes"));
14380 if (hasraw) {
14381 CHECK(putstr(text, "\ninline signing: yes"));
14382 } else {
14383 CHECK(putstr(text, "\ninline signing: no"));
14384 }
14385 } else {
14386 CHECK(putstr(text, "\nsecure: no"));
14387 }
14388
14389 if (maintain) {
14390 CHECK(putstr(text, "\nkey maintenance: automatic"));
14391 if (! isc_time_isepoch(&refreshkeytime)) {
14392 CHECK(putstr(text, "\nnext key event: "));
14393 CHECK(putstr(text, kbuf));
14394 }
14395 } else if (allow) {
14396 CHECK(putstr(text, "\nkey maintenance: on command"));
14397 } else if (secure || hasraw) {
14398 CHECK(putstr(text, "\nkey maintenance: none"));
14399 }
14400
14401 if (!isc_time_isepoch(&resigntime)) {
14402 CHECK(putstr(text, "\nnext resign node: "));
14403 CHECK(putstr(text, resignbuf));
14404 CHECK(putstr(text, "\nnext resign time: "));
14405 CHECK(putstr(text, rtbuf));
14406 }
14407
14408 if (dynamic) {
14409 CHECK(putstr(text, "\ndynamic: yes"));
14410 if (frozen) {
14411 CHECK(putstr(text, "\nfrozen: yes"));
14412 } else {
14413 CHECK(putstr(text, "\nfrozen: no"));
14414 }
14415 } else {
14416 CHECK(putstr(text, "\ndynamic: no"));
14417 }
14418
14419 CHECK(putstr(text, "\nreconfigurable via modzone: "));
14420 CHECK(putstr(text, dns_zone_getadded(zone) ? "yes" : "no"));
14421
14422 cleanup:
14423 /* Indicate truncated output if possible. */
14424 if (result == ISC_R_NOSPACE) {
14425 (void) putstr(text, "\n...");
14426 }
14427 if ((result == ISC_R_SUCCESS || result == ISC_R_NOSPACE)) {
14428 (void) putnull(text);
14429 }
14430
14431 if (db != NULL) {
14432 dns_db_detach(&db);
14433 }
14434 if (rawdb != NULL) {
14435 dns_db_detach(&rawdb);
14436 }
14437 if (incfiles != NULL && mayberaw != NULL) {
14438 int i;
14439 isc_mem_t *mctx = dns_zone_getmctx(mayberaw);
14440
14441 for (i = 0; i < nfiles; i++) {
14442 if (incfiles[i] != NULL) {
14443 isc_mem_free(mctx, incfiles[i]);
14444 }
14445 }
14446 isc_mem_free(mctx, incfiles);
14447 }
14448 if (raw != NULL) {
14449 dns_zone_detach(&raw);
14450 }
14451 if (zone != NULL) {
14452 dns_zone_detach(&zone);
14453 }
14454 return (result);
14455}
14456
14457static inline bool
14458argcheck(char *cmd, const char *full) {
14459 size_t l;
14460
14461 if (cmd == NULL || cmd[0] != '-')
14462 return (false);
14463
14464 cmd++;
14465 l = strlen(cmd);
14466 if (l > strlen(full) || strncasecmp(cmd, full, l) != 0)
14467 return (false);
14468
14469 return (true);
14470}
14471
14472isc_result_t
14473named_server_nta(named_server_t *server, isc_lex_t *lex,
14474 bool readonly, isc_buffer_t **text)
14475{
14476 dns_view_t *view;
14477 dns_ntatable_t *ntatable = NULL;
14478 isc_result_t result = ISC_R_SUCCESS;
14479 char *ptr, *nametext = NULL, *viewname;
14480 char namebuf[DNS_NAME_FORMATSIZE];
14481 char viewbuf[DNS_NAME_FORMATSIZE];
14482 isc_stdtime_t now, when;
14483 isc_time_t t;
14484 char tbuf[64];
14485 const char *msg = NULL;
14486 bool dump = false, force = false;
14487 dns_fixedname_t fn;
14488 const dns_name_t *ntaname;
14489 dns_name_t *fname;
14490 dns_ttl_t ntattl;
14491 bool ttlset = false, excl = false, viewfound = false;
14492 dns_rdataclass_t rdclass = dns_rdataclass_in;
14493 bool first = true;
14494
14495 UNUSED(force);
14496
14497 fname = dns_fixedname_initname(&fn);
14498
14499 /* Skip the command name. */
14500 ptr = next_token(lex, text);
14501 if (ptr == NULL) {
14502 return (ISC_R_UNEXPECTEDEND);
14503 }
14504
14505 for (;;) {
14506
14507 /* Check for options */
14508 ptr = next_token(lex, text);
14509 if (ptr == NULL) {
14510 return (ISC_R_UNEXPECTEDEND);
14511 }
14512
14513 if (strcmp(ptr, "--") == 0) {
14514 break;
14515 } else if (argcheck(ptr, "dump")) {
14516 dump = true;
14517 } else if (argcheck(ptr, "remove")) {
14518 ntattl = 0;
14519 ttlset = true;
14520 } else if (argcheck(ptr, "force")) {
14521 force = true;
14522 continue;
14523 } else if (argcheck(ptr, "lifetime")) {
14524 isc_textregion_t tr;
14525
14526 ptr = next_token(lex, text);
14527 if (ptr == NULL) {
14528 msg = "No lifetime specified";
14529 CHECK(ISC_R_UNEXPECTEDEND);
14530 }
14531
14532 tr.base = ptr;
14533 tr.length = strlen(ptr);
14534 result = dns_ttl_fromtext(&tr, &ntattl);
14535 if (result != ISC_R_SUCCESS) {
14536 msg = "could not parse NTA lifetime";
14537 CHECK(result);
14538 }
14539
14540 if (ntattl > 604800) {
14541 msg = "NTA lifetime cannot exceed one week";
14542 CHECK(ISC_R_RANGE);
14543 }
14544
14545 ttlset = true;
14546 continue;
14547 } else if (argcheck(ptr, "class")) {
14548 isc_textregion_t tr;
14549
14550 ptr = next_token(lex, text);
14551 if (ptr == NULL) {
14552 msg = "No class specified";
14553 CHECK(ISC_R_UNEXPECTEDEND);
14554 }
14555
14556 tr.base = ptr;
14557 tr.length = strlen(ptr);
14558 CHECK(dns_rdataclass_fromtext(&rdclass, &tr));
14559 continue;
14560 } else if (ptr[0] == '-') {
14561 msg = "Unknown option";
14562 CHECK(DNS_R_SYNTAX);
14563 } else {
14564 nametext = ptr;
14565 }
14566
14567 break;
14568 }
14569
14570 /*
14571 * If -dump was specified, list NTA's and return
14572 */
14573 if (dump) {
14574 for (view = ISC_LIST_HEAD(server->viewlist);
14575 view != NULL;
14576 view = ISC_LIST_NEXT(view, link))
14577 {
14578 if (ntatable != NULL) {
14579 dns_ntatable_detach(&ntatable);
14580 }
14581 result = dns_view_getntatable(view, &ntatable);
14582 if (result == ISC_R_NOTFOUND) {
14583 continue;
14584 }
14585
14586 CHECK(dns_ntatable_totext(ntatable, view->name, text));
14587 }
14588 CHECK(putnull(text));
14589
14590 goto cleanup;
14591 }
14592
14593 if (readonly) {
14594 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14595 NAMED_LOGMODULE_CONTROL, ISC_LOG_INFO,
14596 "rejecting restricted control channel "
14597 "NTA command");
14598 CHECK(ISC_R_FAILURE);
14599 }
14600
14601 /* Get the NTA name if not found above. */
14602 if (nametext == NULL) {
14603 nametext = next_token(lex, text);
14604 }
14605 if (nametext == NULL) {
14606 return (ISC_R_UNEXPECTEDEND);
14607 }
14608
14609 /* Copy nametext as it'll be overwritten by next_token() */
14610 strlcpy(namebuf, nametext, DNS_NAME_FORMATSIZE);
14611
14612 if (strcmp(namebuf, ".") == 0) {
14613 ntaname = dns_rootname;
14614 } else {
14615 isc_buffer_t b;
14616 isc_buffer_init(&b, namebuf, strlen(namebuf));
14617 isc_buffer_add(&b, strlen(namebuf));
14618 CHECK(dns_name_fromtext(fname, &b, dns_rootname, 0, NULL));
14619 ntaname = fname;
14620 }
14621
14622 /* Look for the view name. */
14623 viewname = next_token(lex, text);
14624 if (viewname != NULL) {
14625 strlcpy(viewbuf, viewname, DNS_NAME_FORMATSIZE);
14626 viewname = viewbuf;
14627 }
14628
14629 if (next_token(lex, text) != NULL) {
14630 CHECK(DNS_R_SYNTAX);
14631 }
14632
14633 isc_stdtime_get(&now);
14634
14635 result = isc_task_beginexclusive(server->task);
14636 RUNTIME_CHECK(result == ISC_R_SUCCESS);
14637 excl = true;
14638 for (view = ISC_LIST_HEAD(server->viewlist);
14639 view != NULL;
14640 view = ISC_LIST_NEXT(view, link))
14641 {
14642 if (viewname != NULL && strcmp(view->name, viewname) != 0) {
14643 continue;
14644 }
14645 viewfound = true;
14646
14647 if (view->rdclass != rdclass && rdclass != dns_rdataclass_any) {
14648 continue;
14649 }
14650
14651 if (view->nta_lifetime == 0) {
14652 continue;
14653 }
14654
14655 if (!ttlset) {
14656 ntattl = view->nta_lifetime;
14657 }
14658
14659 if (ntatable != NULL) {
14660 dns_ntatable_detach(&ntatable);
14661 }
14662
14663 result = dns_view_getntatable(view, &ntatable);
14664 if (result == ISC_R_NOTFOUND) {
14665 result = ISC_R_SUCCESS;
14666 continue;
14667 }
14668
14669 result = dns_view_flushnode(view, ntaname, true);
14670 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14671 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14672 "flush tree '%s' in cache view '%s': %s",
14673 namebuf, view->name,
14674 isc_result_totext(result));
14675
14676 if (ntattl != 0) {
14677 CHECK(dns_ntatable_add(ntatable, ntaname,
14678 force, now, ntattl));
14679
14680 when = now + ntattl;
14681 isc_time_set(&t, when, 0);
14682 isc_time_formattimestamp(&t, tbuf, sizeof(tbuf));
14683
14684 if (!first) {
14685 CHECK(putstr(text, "\n"));
14686 }
14687 first = false;
14688
14689 CHECK(putstr(text, "Negative trust anchor added: "));
14690 CHECK(putstr(text, namebuf));
14691 CHECK(putstr(text, "/"));
14692 CHECK(putstr(text, view->name));
14693 CHECK(putstr(text, ", expires "));
14694 CHECK(putstr(text, tbuf));
14695
14696 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14697 NAMED_LOGMODULE_SERVER, ISC_LOG_INFO,
14698 "added NTA '%s' (%d sec) in view '%s'",
14699 namebuf, ntattl, view->name);
14700 } else {
14701 bool wasremoved;
14702
14703 result = dns_ntatable_delete(ntatable, ntaname);
14704 if (result == ISC_R_SUCCESS) {
14705 wasremoved = true;
14706 } else if (result == ISC_R_NOTFOUND) {
14707 wasremoved = false;
14708 } else {
14709 goto cleanup;
14710 }
14711
14712 if (!first) {
14713 CHECK(putstr(text, "\n"));
14714 }
14715 first = false;
14716
14717 CHECK(putstr(text, "Negative trust anchor "));
14718 CHECK(putstr(text, wasremoved ? "removed: "
14719 : "not found: "));
14720 CHECK(putstr(text, namebuf));
14721 CHECK(putstr(text, "/"));
14722 CHECK(putstr(text, view->name));
14723
14724 if (wasremoved) {
14725 isc_log_write(named_g_lctx,
14726 NAMED_LOGCATEGORY_GENERAL,
14727 NAMED_LOGMODULE_SERVER,
14728 ISC_LOG_INFO,
14729 "removed NTA '%s' in view %s",
14730 namebuf, view->name);
14731 }
14732 }
14733
14734 result = dns_view_saventa(view);
14735 if (result != ISC_R_SUCCESS) {
14736 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14737 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14738 "error writing NTA file "
14739 "for view '%s': %s",
14740 view->name, isc_result_totext(result));
14741 }
14742 }
14743
14744 if (!viewfound) {
14745 msg = "No such view";
14746 CHECK(ISC_R_NOTFOUND);
14747 }
14748
14749 (void) putnull(text);
14750
14751 cleanup:
14752 if (msg != NULL) {
14753 (void) putstr(text, msg);
14754 (void) putnull(text);
14755 }
14756
14757 if (excl) {
14758 isc_task_endexclusive(server->task);
14759 }
14760 if (ntatable != NULL) {
14761 dns_ntatable_detach(&ntatable);
14762 }
14763 return (result);
14764}
14765
14766isc_result_t
14767named_server_saventa(named_server_t *server) {
14768 dns_view_t *view;
14769
14770 for (view = ISC_LIST_HEAD(server->viewlist);
14771 view != NULL;
14772 view = ISC_LIST_NEXT(view, link))
14773 {
14774 isc_result_t result = dns_view_saventa(view);
14775
14776 if (result != ISC_R_SUCCESS) {
14777 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14778 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14779 "error writing NTA file "
14780 "for view '%s': %s",
14781 view->name, isc_result_totext(result));
14782 }
14783 }
14784
14785 return (ISC_R_SUCCESS);
14786}
14787
14788isc_result_t
14789named_server_loadnta(named_server_t *server) {
14790 dns_view_t *view;
14791
14792 for (view = ISC_LIST_HEAD(server->viewlist);
14793 view != NULL;
14794 view = ISC_LIST_NEXT(view, link))
14795 {
14796 isc_result_t result = dns_view_loadnta(view);
14797
14798 if ((result != ISC_R_SUCCESS) &&
14799 (result != ISC_R_FILENOTFOUND) &&
14800 (result != ISC_R_NOTFOUND))
14801 {
14802 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14803 NAMED_LOGMODULE_SERVER, ISC_LOG_ERROR,
14804 "error loading NTA file "
14805 "for view '%s': %s",
14806 view->name, isc_result_totext(result));
14807 }
14808 }
14809
14810 return (ISC_R_SUCCESS);
14811}
14812
14813static isc_result_t
14814mkey_refresh(dns_view_t *view, isc_buffer_t **text) {
14815 isc_result_t result;
14816 char msg[DNS_NAME_FORMATSIZE + 500] = "";
14817
14818 snprintf(msg, sizeof(msg),
14819 "refreshing managed keys for '%s'", view->name);
14820 CHECK(putstr(text, msg));
14821 CHECK(dns_zone_synckeyzone(view->managed_keys));
14822
14823 cleanup:
14824 return (result);
14825}
14826
14827static isc_result_t
14828mkey_destroy(named_server_t *server, dns_view_t *view, isc_buffer_t **text) {
14829 isc_result_t result;
14830 char msg[DNS_NAME_FORMATSIZE + 500] = "";
14831 bool exclusive = false;
14832 const char *file = NULL;
14833 dns_db_t *dbp = NULL;
14834 dns_zone_t *mkzone = NULL;
14835 bool removed_a_file = false;
14836
14837 if (view->managed_keys == NULL) {
14838 CHECK(ISC_R_NOTFOUND);
14839 }
14840
14841 snprintf(msg, sizeof(msg),
14842 "destroying managed-keys database for '%s'", view->name);
14843 CHECK(putstr(text, msg));
14844
14845 result = isc_task_beginexclusive(server->task);
14846 RUNTIME_CHECK(result == ISC_R_SUCCESS);
14847 exclusive = true;
14848
14849 /* Remove and clean up managed keys zone from view */
14850 mkzone = view->managed_keys;
14851 view->managed_keys = NULL;
14852 (void)dns_zone_flush(mkzone);
14853
14854 /* Unload zone database */
14855 if (dns_zone_getdb(mkzone, &dbp) == ISC_R_SUCCESS) {
14856 dns_db_detach(&dbp);
14857 dns_zone_unload(mkzone);
14858 }
14859
14860 /* Delete files */
14861 file = dns_zone_getfile(mkzone);
14862 result = isc_file_remove(file);
14863 if (result == ISC_R_SUCCESS) {
14864 removed_a_file = true;
14865 } else {
14866 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14867 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14868 "file %s not removed: %s",
14869 file, isc_result_totext(result));
14870 }
14871
14872 file = dns_zone_getjournal(mkzone);
14873 result = isc_file_remove(file);
14874 if (result == ISC_R_SUCCESS) {
14875 removed_a_file = true;
14876 } else {
14877 isc_log_write(named_g_lctx, NAMED_LOGCATEGORY_GENERAL,
14878 NAMED_LOGMODULE_SERVER, ISC_LOG_WARNING,
14879 "file %s not removed: %s",
14880 file, isc_result_totext(result));
14881 }
14882
14883 if (!removed_a_file) {
14884 CHECK(putstr(text, "error: no files could be removed"));
14885 CHECK(ISC_R_FAILURE);
14886 }
14887
14888 dns_zone_detach(&mkzone);
14889 result = ISC_R_SUCCESS;
14890
14891 cleanup:
14892 if (exclusive) {
14893 isc_task_endexclusive(server->task);
14894 }
14895 return (result);
14896}
14897
14898static isc_result_t
14899mkey_dumpzone(dns_view_t *view, isc_buffer_t **text) {
14900 isc_result_t result;
14901 dns_db_t *db = NULL;
14902 dns_dbversion_t *ver = NULL;
14903 dns_rriterator_t rrit;
14904 isc_stdtime_t now;
14905 dns_name_t *prevname = NULL;
14906
14907 isc_stdtime_get(&now);
14908
14909 CHECK(dns_zone_getdb(view->managed_keys, &db));
14910 dns_db_currentversion(db, &ver);
14911 dns_rriterator_init(&rrit, db, ver, 0);
14912 for (result = dns_rriterator_first(&rrit);
14913 result == ISC_R_SUCCESS;
14914 result = dns_rriterator_nextrrset(&rrit))
14915 {
14916 char buf[DNS_NAME_FORMATSIZE + 500];
14917 dns_name_t *name = NULL;
14918 dns_rdataset_t *kdset = NULL;
14919 dns_rdata_t rdata = DNS_RDATA_INIT;
14920 dns_rdata_keydata_t kd;
14921 uint32_t ttl;
14922
14923 dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
14924 if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
14925 !dns_rdataset_isassociated(kdset))
14926 continue;
14927
14928 if (name != prevname) {
14929 char nbuf[DNS_NAME_FORMATSIZE];
14930 dns_name_format(name, nbuf, sizeof(nbuf));
14931 snprintf(buf, sizeof(buf), "\n\n name: %s", nbuf);
14932 CHECK(putstr(text, buf));
14933 }
14934
14935
14936 for (result = dns_rdataset_first(kdset);
14937 result == ISC_R_SUCCESS;
14938 result = dns_rdataset_next(kdset))
14939 {
14940 char alg[DNS_SECALG_FORMATSIZE];
14941 char tbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
14942 dns_keytag_t keyid;
14943 isc_region_t r;
14944 isc_time_t t;
14945 bool revoked;
14946
14947 dns_rdata_reset(&rdata);
14948 dns_rdataset_current(kdset, &rdata);
14949 result = dns_rdata_tostruct(&rdata, &kd, NULL);
14950 RUNTIME_CHECK(result == ISC_R_SUCCESS);
14951
14952 dns_rdata_toregion(&rdata, &r);
14953 isc_region_consume(&r, 12);
14954 keyid = dst_region_computeid(&r);
14955
14956 snprintf(buf, sizeof(buf), "\n keyid: %u", keyid);
14957 CHECK(putstr(text, buf));
14958
14959 dns_secalg_format(kd.algorithm, alg, sizeof(alg));
14960 snprintf(buf, sizeof(buf), "\n\talgorithm: %s", alg);
14961 CHECK(putstr(text, buf));
14962
14963 revoked = ((kd.flags & DNS_KEYFLAG_REVOKE) != 0);
14964 snprintf(buf, sizeof(buf), "\n\tflags:%s%s%s",
14965 revoked ? " REVOKE" : "",
14966 ((kd.flags & DNS_KEYFLAG_KSK) != 0)
14967 ? " SEP" : "",
14968 (kd.flags == 0) ? " (none)" : "");
14969 CHECK(putstr(text, buf));
14970
14971 isc_time_set(&t, kd.refresh, 0);
14972 isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
14973 snprintf(buf, sizeof(buf),
14974 "\n\tnext refresh: %s", tbuf);
14975 CHECK(putstr(text, buf));
14976
14977 if (kd.removehd != 0) {
14978 isc_time_set(&t, kd.removehd, 0);
14979 isc_time_formathttptimestamp(&t, tbuf,
14980 sizeof(tbuf));
14981 snprintf(buf, sizeof(buf),
14982 "\n\tremove at: %s", tbuf);
14983 CHECK(putstr(text, buf));
14984 }
14985
14986 isc_time_set(&t, kd.addhd, 0);
14987 isc_time_formathttptimestamp(&t, tbuf, sizeof(tbuf));
14988 if (kd.addhd == 0)
14989 snprintf(buf, sizeof(buf), "\n\tno trust");
14990 else if (revoked)
14991 snprintf(buf, sizeof(buf),
14992 "\n\ttrust revoked");
14993 else if (kd.addhd <= now)
14994 snprintf(buf, sizeof(buf),
14995 "\n\ttrusted since: %s", tbuf);
14996 else if (kd.addhd > now)
14997 snprintf(buf, sizeof(buf),
14998 "\n\ttrust pending: %s", tbuf);
14999 CHECK(putstr(text, buf));
15000 }
15001 }
15002
15003 if (result == ISC_R_NOMORE)
15004 result = ISC_R_SUCCESS;
15005
15006 cleanup:
15007 if (ver != NULL) {
15008 dns_rriterator_destroy(&rrit);
15009 dns_db_closeversion(db, &ver, false);
15010 }
15011 if (db != NULL)
15012 dns_db_detach(&db);
15013
15014 return (result);
15015}
15016
15017static isc_result_t
15018mkey_status(dns_view_t *view, isc_buffer_t **text) {
15019 isc_result_t result;
15020 char msg[ISC_FORMATHTTPTIMESTAMP_SIZE];
15021 isc_time_t t;
15022
15023 CHECK(putstr(text, "view: "));
15024 CHECK(putstr(text, view->name));
15025
15026 CHECK(putstr(text, "\nnext scheduled event: "));
15027
15028 dns_zone_getrefreshkeytime(view->managed_keys, &t);
15029 if (isc_time_isepoch(&t)) {
15030 CHECK(putstr(text, "never"));
15031 } else {
15032 isc_time_formathttptimestamp(&t, msg, sizeof(msg));
15033 CHECK(putstr(text, msg));
15034 }
15035
15036 CHECK(mkey_dumpzone(view, text));
15037
15038 cleanup:
15039 return (result);
15040}
15041
15042isc_result_t
15043named_server_mkeys(named_server_t *server, isc_lex_t *lex,
15044 isc_buffer_t **text)
15045{
15046 char *cmd, *classtxt, *viewtxt = NULL;
15047 isc_result_t result = ISC_R_SUCCESS;
15048 dns_view_t *view = NULL;
15049 dns_rdataclass_t rdclass;
15050 char msg[DNS_NAME_FORMATSIZE + 500] = "";
15051 enum { NONE, STATUS, REFRESH, SYNC, DESTROY } opt = NONE;
15052 bool found = false;
15053 bool first = true;
15054
15055 /* Skip rndc command name */
15056 cmd = next_token(lex, text);
15057 if (cmd == NULL) {
15058 return (ISC_R_UNEXPECTEDEND);
15059 }
15060
15061 /* Get managed-keys subcommand */
15062 cmd = next_token(lex, text);
15063 if (cmd == NULL) {
15064 return (ISC_R_UNEXPECTEDEND);
15065 }
15066
15067 if (strcasecmp(cmd, "status") == 0) {
15068 opt = STATUS;
15069 } else if (strcasecmp(cmd, "refresh") == 0) {
15070 opt = REFRESH;
15071 } else if (strcasecmp(cmd, "sync") == 0) {
15072 opt = SYNC;
15073 } else if (strcasecmp(cmd, "destroy") == 0) {
15074 opt = DESTROY;
15075 } else {
15076 snprintf(msg, sizeof(msg), "unknown command '%s'", cmd);
15077 (void) putstr(text, msg);
15078 result = ISC_R_UNEXPECTED;
15079 goto cleanup;
15080 }
15081
15082 /* Look for the optional class name. */
15083 classtxt = next_token(lex, text);
15084 if (classtxt != NULL) {
15085 isc_textregion_t r;
15086 r.base = classtxt;
15087 r.length = strlen(classtxt);
15088 result = dns_rdataclass_fromtext(&rdclass, &r);
15089 if (result != ISC_R_SUCCESS) {
15090 snprintf(msg, sizeof(msg),
15091 "unknown class '%s'", classtxt);
15092 (void) putstr(text, msg);
15093 goto cleanup;
15094 }
15095 viewtxt = next_token(lex, text);
15096 }
15097
15098 for (view = ISC_LIST_HEAD(server->viewlist);
15099 view != NULL;
15100 view = ISC_LIST_NEXT(view, link))
15101 {
15102 if (viewtxt != NULL &&
15103 (rdclass != view->rdclass ||
15104 strcmp(view->name, viewtxt) != 0))
15105 {
15106 continue;
15107 }
15108
15109 if (view->managed_keys == NULL) {
15110 if (viewtxt != NULL) {
15111 snprintf(msg, sizeof(msg),
15112 "view '%s': no managed keys", viewtxt);
15113 CHECK(putstr(text, msg));
15114 goto cleanup;
15115 } else {
15116 continue;
15117 }
15118 }
15119
15120 found = true;
15121
15122 switch (opt) {
15123 case REFRESH:
15124 if (!first) {
15125 CHECK(putstr(text, "\n"));
15126 }
15127 CHECK(mkey_refresh(view, text));
15128 break;
15129 case STATUS:
15130 if (!first) {
15131 CHECK(putstr(text, "\n\n"));
15132 }
15133 CHECK(mkey_status(view, text));
15134 break;
15135 case SYNC:
15136 CHECK(dns_zone_flush(view->managed_keys));
15137 break;
15138 case DESTROY:
15139 if (!first) {
15140 CHECK(putstr(text, "\n"));
15141 }
15142 CHECK(mkey_destroy(server, view, text));
15143 break;
15144 default:
15145 INSIST(0);
15146 ISC_UNREACHABLE();
15147 }
15148
15149 if (viewtxt != NULL) {
15150 break;
15151 }
15152 first = false;
15153 }
15154
15155 if (!found) {
15156 CHECK(putstr(text, "no views with managed keys"));
15157 }
15158
15159 cleanup:
15160 if (isc_buffer_usedlength(*text) > 0) {
15161 (void) putnull(text);
15162 }
15163
15164 return (result);
15165}
15166
15167isc_result_t
15168named_server_dnstap(named_server_t *server, isc_lex_t *lex,
15169 isc_buffer_t **text)
15170{
15171#ifdef HAVE_DNSTAP
15172 char *ptr;
15173 isc_result_t result;
15174 bool reopen = false;
15175 int backups = 0;
15176
15177 if (server->dtenv == NULL)
15178 return (ISC_R_NOTFOUND);
15179
15180 /* Check the command name. */
15181 ptr = next_token(lex, text);
15182 if (ptr == NULL)
15183 return (ISC_R_UNEXPECTEDEND);
15184
15185 /* "dnstap-reopen" was used in 9.11.0b1 */
15186 if (strcasecmp(ptr, "dnstap-reopen") == 0) {
15187 reopen = true;
15188 } else {
15189 ptr = next_token(lex, text);
15190 if (ptr == NULL)
15191 return (ISC_R_UNEXPECTEDEND);
15192 }
15193
15194 if (reopen || strcasecmp(ptr, "-reopen") == 0) {
15195 backups = ISC_LOG_ROLLNEVER;
15196 } else if ((strcasecmp(ptr, "-roll") == 0)) {
15197 unsigned int n;
15198 ptr = next_token(lex, text);
15199 if (ptr != NULL) {
15200 unsigned int u;
15201 n = sscanf(ptr, "%u", &u);
15202 if (n != 1U || u > INT_MAX)
15203 return (ISC_R_BADNUMBER);
15204 backups = u;
15205 } else {
15206 backups = ISC_LOG_ROLLINFINITE;
15207 }
15208 } else {
15209 return (DNS_R_SYNTAX);
15210 }
15211
15212 result = dns_dt_reopen(server->dtenv, backups);
15213 return (result);
15214#else
15215 UNUSED(server);
15216 UNUSED(lex);
15217 UNUSED(text);
15218 return (ISC_R_NOTIMPLEMENTED);
15219#endif
15220}
15221
15222isc_result_t
15223named_server_tcptimeouts(isc_lex_t *lex, isc_buffer_t **text) {
15224 char *ptr;
15225 isc_result_t result = ISC_R_SUCCESS;
15226 unsigned int initial, idle, keepalive, advertised;
15227 char msg[128];
15228
15229 /* Skip the command name. */
15230 ptr = next_token(lex, text);
15231 if (ptr == NULL)
15232 return (ISC_R_UNEXPECTEDEND);
15233
15234 ns_server_gettimeouts(named_g_server->sctx,
15235 &initial, &idle, &keepalive, &advertised);
15236
15237 /* Look for optional arguments. */
15238 ptr = next_token(lex, NULL);
15239 if (ptr != NULL) {
15240 CHECK(isc_parse_uint32(&initial, ptr, 10));
15241 if (initial > 1200)
15242 CHECK(ISC_R_RANGE);
15243 if (initial < 25)
15244 CHECK(ISC_R_RANGE);
15245
15246 ptr = next_token(lex, text);
15247 if (ptr == NULL)
15248 return (ISC_R_UNEXPECTEDEND);
15249 CHECK(isc_parse_uint32(&idle, ptr, 10));
15250 if (idle > 1200)
15251 CHECK(ISC_R_RANGE);
15252 if (idle < 1)
15253 CHECK(ISC_R_RANGE);
15254
15255 ptr = next_token(lex, text);
15256 if (ptr == NULL)
15257 return (ISC_R_UNEXPECTEDEND);
15258 CHECK(isc_parse_uint32(&keepalive, ptr, 10));
15259 if (keepalive > MAX_TCP_TIMEOUT)
15260 CHECK(ISC_R_RANGE);
15261 if (keepalive < 1)
15262 CHECK(ISC_R_RANGE);
15263
15264 ptr = next_token(lex, text);
15265 if (ptr == NULL)
15266 return (ISC_R_UNEXPECTEDEND);
15267 CHECK(isc_parse_uint32(&advertised, ptr, 10));
15268 if (advertised > MAX_TCP_TIMEOUT)
15269 CHECK(ISC_R_RANGE);
15270
15271 result = isc_task_beginexclusive(named_g_server->task);
15272 RUNTIME_CHECK(result == ISC_R_SUCCESS);
15273
15274 ns_server_settimeouts(named_g_server->sctx, initial, idle,
15275 keepalive, advertised);
15276
15277 isc_task_endexclusive(named_g_server->task);
15278 }
15279
15280 snprintf(msg, sizeof(msg), "tcp-initial-timeout=%u\n", initial);
15281 CHECK(putstr(text, msg));
15282 snprintf(msg, sizeof(msg), "tcp-idle-timeout=%u\n", idle);
15283 CHECK(putstr(text, msg));
15284 snprintf(msg, sizeof(msg), "tcp-keepalive-timeout=%u\n", keepalive);
15285 CHECK(putstr(text, msg));
15286 snprintf(msg, sizeof(msg), "tcp-advertised-timeout=%u", advertised);
15287 CHECK(putstr(text, msg));
15288
15289 cleanup:
15290 if (isc_buffer_usedlength(*text) > 0)
15291 (void) putnull(text);
15292
15293 return (result);
15294}
15295
15296isc_result_t
15297named_server_servestale(named_server_t *server, isc_lex_t *lex,
15298 isc_buffer_t **text)
15299{
15300 char *ptr, *classtxt, *viewtxt = NULL;
15301 char msg[128];
15302 dns_rdataclass_t rdclass = dns_rdataclass_in;
15303 dns_view_t *view;
15304 bool found = false;
15305 dns_stale_answer_t staleanswersok = dns_stale_answer_conf;
15306 bool wantstatus = false;
15307 isc_result_t result = ISC_R_SUCCESS;
15308 bool exclusive = false;
15309
15310 /* Skip the command name. */
15311 ptr = next_token(lex, text);
15312 if (ptr == NULL)
15313 return (ISC_R_UNEXPECTEDEND);
15314
15315 ptr = next_token(lex, NULL);
15316 if (ptr == NULL)
15317 return (ISC_R_UNEXPECTEDEND);
15318
15319 if (!strcasecmp(ptr, "on") || !strcasecmp(ptr, "yes") ||
15320 !strcasecmp(ptr, "enable") || !strcasecmp(ptr, "true")) {
15321 staleanswersok = dns_stale_answer_yes;
15322 } else if (!strcasecmp(ptr, "off") || !strcasecmp(ptr, "no") ||
15323 !strcasecmp(ptr, "disable") || !strcasecmp(ptr, "false")) {
15324 staleanswersok = dns_stale_answer_no;
15325 } else if (strcasecmp(ptr, "reset") == 0) {
15326 staleanswersok = dns_stale_answer_conf;
15327 } else if (!strcasecmp(ptr, "check") || !strcasecmp(ptr, "status")) {
15328 wantstatus = true;
15329 } else
15330 return (DNS_R_SYNTAX);
15331
15332 /* Look for the optional class name. */
15333 classtxt = next_token(lex, text);
15334 if (classtxt != NULL) {
15335 /* Look for the optional view name. */
15336 viewtxt = next_token(lex, text);
15337 }
15338
15339 if (classtxt != NULL) {
15340 isc_textregion_t r;
15341
15342 r.base = classtxt;
15343 r.length = strlen(classtxt);
15344 result = dns_rdataclass_fromtext(&rdclass, &r);
15345 if (result != ISC_R_SUCCESS) {
15346 if (viewtxt != NULL) {
15347 snprintf(msg, sizeof(msg),
15348 "unknown class '%s'", classtxt);
15349 (void) putstr(text, msg);
15350 goto cleanup;
15351 }
15352
15353 viewtxt = classtxt;
15354 classtxt = NULL;
15355 }
15356 }
15357
15358 result = isc_task_beginexclusive(server->task);
15359 RUNTIME_CHECK(result == ISC_R_SUCCESS);
15360 exclusive = true;
15361
15362 for (view = ISC_LIST_HEAD(server->viewlist);
15363 view != NULL;
15364 view = ISC_LIST_NEXT(view, link))
15365 {
15366 dns_ttl_t stale_ttl = 0;
15367 dns_db_t *db = NULL;
15368
15369 if (classtxt != NULL && rdclass != view->rdclass)
15370 continue;
15371
15372 if (viewtxt != NULL && strcmp(view->name, viewtxt) != 0)
15373 continue;
15374
15375 if (!wantstatus) {
15376 view->staleanswersok = staleanswersok;
15377 found = true;
15378 continue;
15379 }
15380
15381 db = NULL;
15382 dns_db_attach(view->cachedb, &db);
15383 (void)dns_db_getservestalettl(db, &stale_ttl);
15384 dns_db_detach(&db);
15385 if (found)
15386 CHECK(putstr(text, "\n"));
15387 CHECK(putstr(text, view->name));
15388 CHECK(putstr(text, ": "));
15389 switch (view->staleanswersok) {
15390 case dns_stale_answer_yes:
15391 if (stale_ttl > 0)
15392 CHECK(putstr(text, "on (rndc)"));
15393 else
15394 CHECK(putstr(text, "off (not-cached)"));
15395 break;
15396 case dns_stale_answer_no:
15397 CHECK(putstr(text, "off (rndc)"));
15398 break;
15399 case dns_stale_answer_conf:
15400 if (view->staleanswersenable && stale_ttl > 0)
15401 CHECK(putstr(text, "on"));
15402 else if (view->staleanswersenable)
15403 CHECK(putstr(text, "off (not-cached)"));
15404 else
15405 CHECK(putstr(text, "off"));
15406 break;
15407 }
15408 if (stale_ttl > 0) {
15409 snprintf(msg, sizeof(msg),
15410 " (stale-answer-ttl=%u max-stale-ttl=%u)",
15411 view->staleanswerttl, stale_ttl);
15412 CHECK(putstr(text, msg));
15413 }
15414 found = true;
15415 }
15416
15417 if (!found)
15418 result = ISC_R_NOTFOUND;
15419
15420cleanup:
15421 if (exclusive)
15422 isc_task_endexclusive(named_g_server->task);
15423
15424 if (isc_buffer_usedlength(*text) > 0)
15425 (void) putnull(text);
15426
15427 return (result);
15428}
15429